mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 03:51:18 +00:00
math::overflow_* wrappers incorrectly don't allow distinct integers #2221.
This commit is contained in:
@@ -184,6 +184,22 @@ macro bool is_ref_indexable($Type) @const
|
||||
return $defined(&($Type){}[0]);
|
||||
}
|
||||
|
||||
macro bool is_flat_intlike($Type) @const
|
||||
{
|
||||
$echo $Type.nameof;
|
||||
$switch $Type.kindof:
|
||||
$case SIGNED_INT:
|
||||
$case UNSIGNED_INT:
|
||||
return true;
|
||||
$case VECTOR:
|
||||
return is_flat_intlike($Type.inner);
|
||||
$case DISTINCT:
|
||||
return is_flat_intlike($Type.inner);
|
||||
$default:
|
||||
return false;
|
||||
$endswitch
|
||||
}
|
||||
|
||||
macro bool is_intlike($Type) @const
|
||||
{
|
||||
$switch $Type.kindof:
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
module std::core::values;
|
||||
import std::core::types;
|
||||
|
||||
|
||||
macro typeid @typeid(#value) @const @builtin => $typeof(#value).typeid;
|
||||
macro TypeKind @typekind(#value) @const @builtin => $typeof(#value).kindof;
|
||||
@@ -9,6 +11,7 @@ macro bool @typeis(#value, $Type) @const @builtin => $typeof(#value).typeid == $
|
||||
macro bool @is_same_type(#value1, #value2) @const => $typeof(#value1).typeid == $typeof(#value2).typeid;
|
||||
macro bool @is_bool(#value) @const => types::is_bool($typeof(#value));
|
||||
macro bool @is_int(#value) @const => types::is_int($typeof(#value));
|
||||
macro bool @is_flat_intlike(#value) @const => types::is_flat_intlike($typeof(#value));
|
||||
macro bool @is_floatlike(#value) @const => types::is_floatlike($typeof(#value));
|
||||
macro bool @is_float(#value) @const => types::is_float($typeof(#value));
|
||||
macro bool @is_promotable_to_floatlike(#value) @const => types::is_promotable_to_floatlike($typeof(#value));
|
||||
|
||||
@@ -1117,7 +1117,7 @@ macro overflow_mul_helper(x, y) @local
|
||||
@param [&out] out : "Where the result of the addition is stored"
|
||||
@return "Whether the addition resulted in an integer overflow"
|
||||
@require values::@is_same_type(a, b) : "a and b must be the same type"
|
||||
@require values::@is_int(a) &&& values::@is_int(b) : "a and b must both be integers"
|
||||
@require values::@is_flat_intlike(a) &&& values::@is_flat_intlike(b) : "a and b must both be integer or integer vector based"
|
||||
@require $defined(*out) &&& values::@is_same_type(*out, a) : "out must be a pointer of the same type as a and b"
|
||||
*>
|
||||
macro bool overflow_add(a, b, out) => $$overflow_add(a, b, out);
|
||||
@@ -1126,7 +1126,7 @@ macro bool overflow_add(a, b, out) => $$overflow_add(a, b, out);
|
||||
@param [&out] out : "Where the result of the subtraction is stored"
|
||||
@return "Whether the subtraction resulted in an integer overflow"
|
||||
@require values::@is_same_type(a, b) : "a and b must be the same type"
|
||||
@require values::@is_int(a) &&& values::@is_int(b) : "a and b must both be integers"
|
||||
@require values::@is_flat_intlike(a) &&& values::@is_flat_intlike(b) : "a and b must both be integer or integer vector based"
|
||||
@require $defined(*out) &&& values::@is_same_type(*out, a) : "out must be a pointer of the same type as a and b"
|
||||
*>
|
||||
macro bool overflow_sub(a, b, out) => $$overflow_sub(a, b, out);
|
||||
@@ -1135,7 +1135,7 @@ macro bool overflow_sub(a, b, out) => $$overflow_sub(a, b, out);
|
||||
@param [&out] out : "Where the result of the multiplication is stored"
|
||||
@return "Whether the multiplication resulted in an integer overflow"
|
||||
@require values::@is_same_type(a, b) : "a and b must be the same type"
|
||||
@require values::@is_int(a) &&& values::@is_int(b) : "a and b must both be integers"
|
||||
@require values::@is_flat_intlike(a) &&& values::@is_flat_intlike(b) : "a and b must both be integer or integer vector based"
|
||||
@require $defined(*out) &&& values::@is_same_type(*out, a) : "out must be a pointer of the same type as a and b"
|
||||
*>
|
||||
macro bool overflow_mul(a, b, out) => $$overflow_mul(a, b, out);
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
- Lambda C-style vaargs were not properly rejected, leading to crash #2229.
|
||||
- Incorrect handling of constant null fault causing compiler crash #2232.
|
||||
- Overload resolution fixes to inline typedef #2226.
|
||||
- `math::overflow_*` wrappers incorrectly don't allow distinct integers #2221.
|
||||
|
||||
### Stdlib changes
|
||||
- Deprecate `String.is_zstr` and `String.quick_zstr` #2188.
|
||||
|
||||
@@ -629,7 +629,7 @@ bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr)
|
||||
case BUILTIN_OVERFLOW_SUB:
|
||||
ASSERT(arg_count == 3);
|
||||
if (!sema_check_builtin_args(context, args,
|
||||
(BuiltinArg[]) {BA_INTEGER, BA_INTEGER, BA_POINTER},
|
||||
(BuiltinArg[]) {BA_INTLIKE, BA_INTLIKE, BA_POINTER},
|
||||
3)) return false;
|
||||
if (!sema_check_builtin_args_match(context, args, 2)) return false;
|
||||
if (type_no_optional(args[0]->type->canonical) != type_no_optional(args[2]->type->canonical->pointer))
|
||||
|
||||
@@ -382,7 +382,7 @@ FunctionPrototype *type_get_resolved_prototype(Type *type)
|
||||
bool type_flat_is_numlike(Type *type)
|
||||
{
|
||||
type = type_flatten(type);
|
||||
if (type->type_kind == TYPE_VECTOR) type = type->array.base;
|
||||
if (type->type_kind == TYPE_VECTOR) type = type_flatten(type->array.base);
|
||||
TypeKind kind = type->type_kind;
|
||||
return kind >= TYPE_NUM_FIRST && kind <= TYPE_NUM_LAST;
|
||||
}
|
||||
@@ -390,7 +390,7 @@ bool type_flat_is_numlike(Type *type)
|
||||
bool type_flat_is_floatlike(Type *type)
|
||||
{
|
||||
type = type_flatten(type);
|
||||
if (type->type_kind == TYPE_VECTOR) type = type->array.base;
|
||||
if (type->type_kind == TYPE_VECTOR) type = type_flatten(type->array.base);
|
||||
TypeKind kind = type->type_kind;
|
||||
return kind >= TYPE_FLOAT_FIRST && kind <= TYPE_FLOAT_LAST;
|
||||
}
|
||||
@@ -398,7 +398,7 @@ bool type_flat_is_floatlike(Type *type)
|
||||
bool type_flat_is_intlike(Type *type)
|
||||
{
|
||||
type = type_flatten(type);
|
||||
if (type->type_kind == TYPE_VECTOR) type = type->array.base;
|
||||
if (type->type_kind == TYPE_VECTOR) type = type_flatten(type->array.base);
|
||||
TypeKind kind = type->type_kind;
|
||||
return kind >= TYPE_INTEGER_FIRST && kind <= TYPE_INTEGER_LAST;
|
||||
}
|
||||
@@ -406,7 +406,7 @@ bool type_flat_is_intlike(Type *type)
|
||||
bool type_flat_is_boolintlike(Type *type)
|
||||
{
|
||||
type = type_flatten(type);
|
||||
if (type->type_kind == TYPE_VECTOR) type = type->array.base;
|
||||
if (type->type_kind == TYPE_VECTOR) type = type_flatten(type->array.base);
|
||||
TypeKind kind = type->type_kind;
|
||||
return kind == TYPE_BOOL || (kind >= TYPE_INTEGER_FIRST && kind <= TYPE_INTEGER_LAST);
|
||||
}
|
||||
|
||||
83
test/test_suite/builtins/math_overflow.c3t
Normal file
83
test/test_suite/builtins/math_overflow.c3t
Normal file
@@ -0,0 +1,83 @@
|
||||
// #target: macos-x64
|
||||
module test;
|
||||
import std::math;
|
||||
typedef Foo = int;
|
||||
|
||||
fn int main()
|
||||
{
|
||||
|
||||
Foo a, b, c;
|
||||
math::overflow_mul(a, b, &c);
|
||||
int[<2>] ab, bb, cb;
|
||||
math::overflow_mul(ab, bb, &cb);
|
||||
Foo[<2>] av, bv, cv;
|
||||
math::overflow_mul(av, bv, &cv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* #expect: test.ll
|
||||
|
||||
define i32 @main() #0 {
|
||||
entry:
|
||||
%a = alloca i32, align 4
|
||||
%b = alloca i32, align 4
|
||||
%c = alloca i32, align 4
|
||||
%a1 = alloca i32, align 4
|
||||
%b2 = alloca i32, align 4
|
||||
%ab = alloca <2 x i32>, align 8
|
||||
%bb = alloca <2 x i32>, align 8
|
||||
%cb = alloca <2 x i32>, align 8
|
||||
%a3 = alloca <2 x i32>, align 8
|
||||
%b4 = alloca <2 x i32>, align 8
|
||||
%av = alloca <2 x i32>, align 8
|
||||
%bv = alloca <2 x i32>, align 8
|
||||
%cv = alloca <2 x i32>, align 8
|
||||
%a6 = alloca <2 x i32>, align 8
|
||||
%b7 = alloca <2 x i32>, align 8
|
||||
store i32 0, ptr %a, align 4
|
||||
store i32 0, ptr %b, align 4
|
||||
store i32 0, ptr %c, align 4
|
||||
%0 = load i32, ptr %a, align 4
|
||||
store i32 %0, ptr %a1, align 4
|
||||
%1 = load i32, ptr %b, align 4
|
||||
store i32 %1, ptr %b2, align 4
|
||||
%neq = icmp ne ptr %c, null
|
||||
call void @llvm.assume(i1 %neq)
|
||||
%2 = load i32, ptr %a1, align 4
|
||||
%3 = load i32, ptr %b2, align 4
|
||||
%4 = call { i32, i1 } @llvm.smul.with.overflow.i32(i32 %2, i32 %3)
|
||||
%5 = extractvalue { i32, i1 } %4, 1
|
||||
%6 = extractvalue { i32, i1 } %4, 0
|
||||
store i32 %6, ptr %c, align 4
|
||||
store <2 x i32> zeroinitializer, ptr %ab, align 8
|
||||
store <2 x i32> zeroinitializer, ptr %bb, align 8
|
||||
store <2 x i32> zeroinitializer, ptr %cb, align 8
|
||||
%7 = load <2 x i32>, ptr %ab, align 8
|
||||
store <2 x i32> %7, ptr %a3, align 8
|
||||
%8 = load <2 x i32>, ptr %bb, align 8
|
||||
store <2 x i32> %8, ptr %b4, align 8
|
||||
%neq5 = icmp ne ptr %cb, null
|
||||
call void @llvm.assume(i1 %neq5)
|
||||
%9 = load <2 x i32>, ptr %a3, align 8
|
||||
%10 = load <2 x i32>, ptr %b4, align 8
|
||||
%11 = call { <2 x i32>, <2 x i1> } @llvm.smul.with.overflow.v2i32(<2 x i32> %9, <2 x i32> %10)
|
||||
%12 = extractvalue { <2 x i32>, <2 x i1> } %11, 1
|
||||
%13 = extractvalue { <2 x i32>, <2 x i1> } %11, 0
|
||||
store <2 x i32> %13, ptr %cb, align 8
|
||||
store <2 x i32> zeroinitializer, ptr %av, align 8
|
||||
store <2 x i32> zeroinitializer, ptr %bv, align 8
|
||||
store <2 x i32> zeroinitializer, ptr %cv, align 8
|
||||
%14 = load <2 x i32>, ptr %av, align 8
|
||||
store <2 x i32> %14, ptr %a6, align 8
|
||||
%15 = load <2 x i32>, ptr %bv, align 8
|
||||
store <2 x i32> %15, ptr %b7, align 8
|
||||
%neq8 = icmp ne ptr %cv, null
|
||||
call void @llvm.assume(i1 %neq8)
|
||||
%16 = load <2 x i32>, ptr %a6, align 8
|
||||
%17 = load <2 x i32>, ptr %b7, align 8
|
||||
%18 = call { <2 x i32>, <2 x i1> } @llvm.smul.with.overflow.v2i32(<2 x i32> %16, <2 x i32> %17)
|
||||
%19 = extractvalue { <2 x i32>, <2 x i1> } %18, 1
|
||||
%20 = extractvalue { <2 x i32>, <2 x i1> } %18, 0
|
||||
store <2 x i32> %20, ptr %cv, align 8
|
||||
ret i32 0
|
||||
}
|
||||
Reference in New Issue
Block a user