From 4664008a7e69735f25693223b78c7ec8c18b9690 Mon Sep 17 00:00:00 2001 From: Matthew Curtis Date: Fri, 7 Mar 2025 11:16:28 -0600 Subject: [PATCH 1/2] [clang] Add builtins for `add` with `nuw` and/or `nsw` --- clang/include/clang/Basic/Builtins.td | 60 +++++++++++++ clang/lib/CodeGen/CGBuiltin.cpp | 48 +++++++++++ clang/test/CodeGen/builtins-int-wrap.c | 111 +++++++++++++++++++++++++ 3 files changed, 219 insertions(+) create mode 100644 clang/test/CodeGen/builtins-int-wrap.c diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 2268df70927a7..ba9250516ec1b 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -5037,6 +5037,66 @@ def ArithmeticFence : LangBuiltin<"ALL_LANGUAGES"> { let Prototype = "void(...)"; } +class SNUWTemplate : + Template<["int", "long int", "long long int"], + ["_nuw", "l_nuw", "ll_nuw"]>; + +class SNSWTemplate : + Template<["int", "long int", "long long int"], + ["_nsw", "l_nsw", "ll_nsw"]>; + +class SNXWTemplate : + Template<["int", "long int", "long long int"], + ["_nuw_nsw", "l_nuw_nsw", "ll_nuw_nsw"]>; + +def SAddNUW : Builtin, SNUWTemplate { + let Spellings = ["__builtin_sadd"]; + let Attributes = [NoThrow]; + let Prototype = "T(T const, T const)"; +} + +def SAddNSW : Builtin, SNSWTemplate { + let Spellings = ["__builtin_sadd"]; + let Attributes = [NoThrow]; + let Prototype = "T(T const, T const)"; +} + +def SAddNXW : Builtin, SNXWTemplate { + let Spellings = ["__builtin_sadd"]; + let Attributes = [NoThrow]; + let Prototype = "T(T const, T const)"; +} + +class UNUWTemplate : + Template<["unsigned int", "unsigned long int", "unsigned long long int"], + ["_nuw", "l_nuw", "ll_nuw"]>; + +class UNSWTemplate : + Template<["unsigned int", "unsigned long int", "unsigned long long int"], + ["_nsw", "l_nsw", "ll_nsw"]>; + +class UNXWTemplate : + Template<["unsigned int", "unsigned long int", "unsigned long long int"], + ["_nuw_nsw", "l_nuw_nsw", "ll_nuw_nsw"]>; + +def UAddNUW : Builtin, UNUWTemplate { + let Spellings = ["__builtin_uadd"]; + let Attributes = [NoThrow]; + let Prototype = "T(T const, T const)"; +} + +def UAddNSW : Builtin, UNSWTemplate { + let Spellings = ["__builtin_uadd"]; + let Attributes = [NoThrow]; + let Prototype = "T(T const, T const)"; +} + +def UAddNXW : Builtin, UNXWTemplate { + let Spellings = ["__builtin_uadd"]; + let Attributes = [NoThrow]; + let Prototype = "T(T const, T const)"; +} + def CountedByRef : Builtin { let Spellings = ["__builtin_counted_by_ref"]; let Attributes = [NoThrow, CustomTypeChecking]; diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index ba78de049ce96..ab711043580ae 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -6616,6 +6616,54 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, auto Str = CGM.GetAddrOfConstantCString(Name, ""); return RValue::get(Str.getPointer()); } + + case Builtin::BI__builtin_sadd_nuw: + case Builtin::BI__builtin_saddl_nuw: + case Builtin::BI__builtin_saddll_nuw: + case Builtin::BI__builtin_uadd_nuw: + case Builtin::BI__builtin_uaddl_nuw: + case Builtin::BI__builtin_uaddll_nuw: + + case Builtin::BI__builtin_sadd_nsw: + case Builtin::BI__builtin_saddl_nsw: + case Builtin::BI__builtin_saddll_nsw: + case Builtin::BI__builtin_uadd_nsw: + case Builtin::BI__builtin_uaddl_nsw: + case Builtin::BI__builtin_uaddll_nsw: + + case Builtin::BI__builtin_sadd_nuw_nsw: + case Builtin::BI__builtin_saddl_nuw_nsw: + case Builtin::BI__builtin_saddll_nuw_nsw: + case Builtin::BI__builtin_uadd_nuw_nsw: + case Builtin::BI__builtin_uaddl_nuw_nsw: + case Builtin::BI__builtin_uaddll_nuw_nsw: { + bool NUW = false; + bool NSW = false; + switch (BuiltinIDIfNoAsmLabel) { + case Builtin::BI__builtin_sadd_nuw: + case Builtin::BI__builtin_saddl_nuw: + case Builtin::BI__builtin_saddll_nuw: + case Builtin::BI__builtin_uadd_nuw: + case Builtin::BI__builtin_uaddl_nuw: + case Builtin::BI__builtin_uaddll_nuw: + NUW = true; + break; + case Builtin::BI__builtin_sadd_nsw: + case Builtin::BI__builtin_saddl_nsw: + case Builtin::BI__builtin_saddll_nsw: + case Builtin::BI__builtin_uadd_nsw: + case Builtin::BI__builtin_uaddl_nsw: + case Builtin::BI__builtin_uaddll_nsw: + NSW = true; + break; + default: + NUW = NSW = true; + break; + } + llvm::Value *X = EmitScalarExpr(E->getArg(0)); + llvm::Value *Y = EmitScalarExpr(E->getArg(1)); + return RValue::get(Builder.CreateAdd(X, Y, "add", NUW, NSW)); + } } // If this is an alias for a lib function (e.g. __builtin_sin), emit diff --git a/clang/test/CodeGen/builtins-int-wrap.c b/clang/test/CodeGen/builtins-int-wrap.c new file mode 100644 index 0000000000000..16eb92681fcc1 --- /dev/null +++ b/clang/test/CodeGen/builtins-int-wrap.c @@ -0,0 +1,111 @@ +// Test CodeGen for nuw/nsw builtins. + +// RUN: %clang_cc1 -triple "x86_64-unknown-unknown" -emit-llvm -x c %s -o - | FileCheck %s + +//------------------------------------------------------------------------------ +// int +//------------------------------------------------------------------------------ +int test_sadd_nuw(int x, int y) { return __builtin_sadd_nuw(x, y); } +// CHECK-LABEL: @test_sadd_nuw +// CHECK: [[RV:%.+]] = add nuw i32 +// CHECK: ret i32 [[RV]] + +int test_sadd_nsw(int x, int y) { return __builtin_sadd_nsw(x, y); } +// CHECK-LABEL: @test_sadd_nsw +// CHECK: [[RV:%.+]] = add nsw i32 +// CHECK: ret i32 [[RV]] + +int test_sadd_nuw_nsw(int x, int y) { return __builtin_sadd_nuw_nsw(x, y); } +// CHECK-LABEL: @test_sadd_nuw_nsw +// CHECK: [[RV:%.+]] = add nuw nsw i32 +// CHECK: ret i32 [[RV]] + +//------------------------------------------------------------------------------ +// long int +//------------------------------------------------------------------------------ +long int test_saddl_nuw(long int x, long int y) { return __builtin_saddl_nuw(x, y); } +// CHECK-LABEL: @test_saddl_nuw +// CHECK: [[RV:%.+]] = add nuw i64 +// CHECK: ret i64 [[RV]] + +long int test_saddl_nsw(long int x, long int y) { return __builtin_saddl_nsw(x, y); } +// CHECK-LABEL: @test_saddl_nsw +// CHECK: [[RV:%.+]] = add nsw i64 +// CHECK: ret i64 [[RV]] + +long int test_saddl_nuw_nsw(long int x, long int y) { return __builtin_saddl_nuw_nsw(x, y); } +// CHECK-LABEL: @test_saddl_nuw_nsw +// CHECK: [[RV:%.+]] = add nuw nsw i64 +// CHECK: ret i64 [[RV]] + +//------------------------------------------------------------------------------ +// long int +//------------------------------------------------------------------------------ +long long int test_saddll_nuw(long long int x, long long int y) { return __builtin_saddll_nuw(x, y); } +// CHECK-LABEL: @test_saddll_nuw +// CHECK: [[RV:%.+]] = add nuw i64 +// CHECK: ret i64 [[RV]] + +long long int test_saddll_nsw(long long int x, long long int y) { return __builtin_saddll_nsw(x, y); } +// CHECK-LABEL: @test_saddll_nsw +// CHECK: [[RV:%.+]] = add nsw i64 +// CHECK: ret i64 [[RV]] + +long long int test_saddll_nuw_nsw(long long int x, long long int y) { return __builtin_saddll_nuw_nsw(x, y); } +// CHECK-LABEL: @test_saddll_nuw_nsw +// CHECK: [[RV:%.+]] = add nuw nsw i64 +// CHECK: ret i64 [[RV]] + +//------------------------------------------------------------------------------ +// unsigned int +//------------------------------------------------------------------------------ +unsigned int test_uadd_nuw(unsigned int x, unsigned int y) { return __builtin_uadd_nuw(x, y); } +// CHECK-LABEL: @test_uadd_nuw +// CHECK: [[RV:%.+]] = add nuw i32 +// CHECK: ret i32 [[RV]] + +unsigned int test_uadd_nsw(unsigned int x, unsigned int y) { return __builtin_uadd_nsw(x, y); } +// CHECK-LABEL: @test_uadd_nsw +// CHECK: [[RV:%.+]] = add nsw i32 +// CHECK: ret i32 [[RV]] + +unsigned int test_uadd_nuw_nsw(unsigned int x, unsigned int y) { return __builtin_uadd_nuw_nsw(x, y); } +// CHECK-LABEL: @test_uadd_nuw_nsw +// CHECK: [[RV:%.+]] = add nuw nsw i32 +// CHECK: ret i32 [[RV]] + +//------------------------------------------------------------------------------ +// unsigned long int +//------------------------------------------------------------------------------ +unsigned long int test_uaddl_nuw(unsigned long int x, unsigned long int y) { return __builtin_uaddl_nuw(x, y); } +// CHECK-LABEL: @test_uaddl_nuw +// CHECK: [[RV:%.+]] = add nuw i64 +// CHECK: ret i64 [[RV]] + +unsigned long int test_uaddl_nsw(unsigned long int x, unsigned long int y) { return __builtin_uaddl_nsw(x, y); } +// CHECK-LABEL: @test_uaddl_nsw +// CHECK: [[RV:%.+]] = add nsw i64 +// CHECK: ret i64 [[RV]] + +unsigned long int test_uaddl_nuw_nsw(unsigned long int x, unsigned long int y) { return __builtin_uaddl_nuw_nsw(x, y); } +// CHECK-LABEL: @test_uaddl_nuw_nsw +// CHECK: [[RV:%.+]] = add nuw nsw i64 +// CHECK: ret i64 [[RV]] + +//------------------------------------------------------------------------------ +// unsigned long long int +//------------------------------------------------------------------------------ +unsigned long long int test_uaddll_nuw(unsigned long long int x, unsigned long long int y) { return __builtin_uaddll_nuw(x, y); } +// CHECK-LABEL: @test_uaddll_nuw +// CHECK: [[RV:%.+]] = add nuw i64 +// CHECK: ret i64 [[RV]] + +unsigned long long int test_uaddll_nsw(unsigned long long int x, unsigned long long int y) { return __builtin_uaddll_nsw(x, y); } +// CHECK-LABEL: @test_uaddll_nsw +// CHECK: [[RV:%.+]] = add nsw i64 +// CHECK: ret i64 [[RV]] + +unsigned long long int test_uaddll_nuw_nsw(unsigned long long int x, unsigned long long int y) { return __builtin_uaddll_nuw_nsw(x, y); } +// CHECK-LABEL: @test_uaddll_nuw_nsw +// CHECK: [[RV:%.+]] = add nuw nsw i64 +// CHECK: ret i64 [[RV]] From 58f679c1cd096820c07ecfc6cb1129b7be7b64a7 Mon Sep 17 00:00:00 2001 From: Matthew Curtis Date: Mon, 10 Mar 2025 18:00:08 -0500 Subject: [PATCH 2/2] fixup! [clang] Add builtins for `add` with `nuw` and/or `nsw` Rework non-wrapping add builtins to be generic --- clang/include/clang/Basic/Builtins.td | 66 ++++------------- .../clang/Basic/DiagnosticSemaKinds.td | 3 + clang/lib/CodeGen/CGBuiltin.cpp | 49 ++----------- clang/lib/Sema/SemaChecking.cpp | 34 +++++++++ clang/test/CodeGen/builtins-int-wrap.c | 72 +++++++++---------- clang/test/Sema/builtins-int-wrap.c | 22 ++++++ 6 files changed, 113 insertions(+), 133 deletions(-) create mode 100644 clang/test/Sema/builtins-int-wrap.c diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index ba9250516ec1b..e94cb6fb274e2 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -5037,64 +5037,22 @@ def ArithmeticFence : LangBuiltin<"ALL_LANGUAGES"> { let Prototype = "void(...)"; } -class SNUWTemplate : - Template<["int", "long int", "long long int"], - ["_nuw", "l_nuw", "ll_nuw"]>; - -class SNSWTemplate : - Template<["int", "long int", "long long int"], - ["_nsw", "l_nsw", "ll_nsw"]>; - -class SNXWTemplate : - Template<["int", "long int", "long long int"], - ["_nuw_nsw", "l_nuw_nsw", "ll_nuw_nsw"]>; - -def SAddNUW : Builtin, SNUWTemplate { - let Spellings = ["__builtin_sadd"]; - let Attributes = [NoThrow]; - let Prototype = "T(T const, T const)"; -} - -def SAddNSW : Builtin, SNSWTemplate { - let Spellings = ["__builtin_sadd"]; - let Attributes = [NoThrow]; - let Prototype = "T(T const, T const)"; -} - -def SAddNXW : Builtin, SNXWTemplate { - let Spellings = ["__builtin_sadd"]; - let Attributes = [NoThrow]; - let Prototype = "T(T const, T const)"; -} - -class UNUWTemplate : - Template<["unsigned int", "unsigned long int", "unsigned long long int"], - ["_nuw", "l_nuw", "ll_nuw"]>; - -class UNSWTemplate : - Template<["unsigned int", "unsigned long int", "unsigned long long int"], - ["_nsw", "l_nsw", "ll_nsw"]>; - -class UNXWTemplate : - Template<["unsigned int", "unsigned long int", "unsigned long long int"], - ["_nuw_nsw", "l_nuw_nsw", "ll_nuw_nsw"]>; - -def UAddNUW : Builtin, UNUWTemplate { - let Spellings = ["__builtin_uadd"]; - let Attributes = [NoThrow]; - let Prototype = "T(T const, T const)"; +def AddNUW : Builtin { + let Spellings = ["__builtin_add_nuw"]; + let Attributes = [CustomTypeChecking, NoThrow]; + let Prototype = "void(...)"; } -def UAddNSW : Builtin, UNSWTemplate { - let Spellings = ["__builtin_uadd"]; - let Attributes = [NoThrow]; - let Prototype = "T(T const, T const)"; +def AddNSW : Builtin { + let Spellings = ["__builtin_add_nsw"]; + let Attributes = [CustomTypeChecking, NoThrow]; + let Prototype = "void(...)"; } -def UAddNXW : Builtin, UNXWTemplate { - let Spellings = ["__builtin_uadd"]; - let Attributes = [NoThrow]; - let Prototype = "T(T const, T const)"; +def AddNW : Builtin { + let Spellings = ["__builtin_add_nuw_nsw"]; + let Attributes = [CustomTypeChecking, NoThrow]; + let Prototype = "void(...)"; } def CountedByRef : Builtin { diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 239f16769ace9..bdb63ab1daa2b 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -12527,6 +12527,9 @@ def err_builtin_matrix_stride_too_small: Error< def err_builtin_matrix_invalid_dimension: Error< "%0 dimension is outside the allowed range [1, %1]">; +def err_builtin_add_nxw_invalid_arg : Error< + "both arguments must be of integral type but %ordinal0 argument is %1">; + def warn_mismatched_import : Warning< "import %select{module|name}0 (%1) does not match the import %select{module|name}0 (%2) of the " "previous declaration">, diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index ab711043580ae..0f87408d8fb0d 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -6617,49 +6617,12 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, return RValue::get(Str.getPointer()); } - case Builtin::BI__builtin_sadd_nuw: - case Builtin::BI__builtin_saddl_nuw: - case Builtin::BI__builtin_saddll_nuw: - case Builtin::BI__builtin_uadd_nuw: - case Builtin::BI__builtin_uaddl_nuw: - case Builtin::BI__builtin_uaddll_nuw: - - case Builtin::BI__builtin_sadd_nsw: - case Builtin::BI__builtin_saddl_nsw: - case Builtin::BI__builtin_saddll_nsw: - case Builtin::BI__builtin_uadd_nsw: - case Builtin::BI__builtin_uaddl_nsw: - case Builtin::BI__builtin_uaddll_nsw: - - case Builtin::BI__builtin_sadd_nuw_nsw: - case Builtin::BI__builtin_saddl_nuw_nsw: - case Builtin::BI__builtin_saddll_nuw_nsw: - case Builtin::BI__builtin_uadd_nuw_nsw: - case Builtin::BI__builtin_uaddl_nuw_nsw: - case Builtin::BI__builtin_uaddll_nuw_nsw: { - bool NUW = false; - bool NSW = false; - switch (BuiltinIDIfNoAsmLabel) { - case Builtin::BI__builtin_sadd_nuw: - case Builtin::BI__builtin_saddl_nuw: - case Builtin::BI__builtin_saddll_nuw: - case Builtin::BI__builtin_uadd_nuw: - case Builtin::BI__builtin_uaddl_nuw: - case Builtin::BI__builtin_uaddll_nuw: - NUW = true; - break; - case Builtin::BI__builtin_sadd_nsw: - case Builtin::BI__builtin_saddl_nsw: - case Builtin::BI__builtin_saddll_nsw: - case Builtin::BI__builtin_uadd_nsw: - case Builtin::BI__builtin_uaddl_nsw: - case Builtin::BI__builtin_uaddll_nsw: - NSW = true; - break; - default: - NUW = NSW = true; - break; - } + case Builtin::BI__builtin_add_nuw: + case Builtin::BI__builtin_add_nsw: + case Builtin::BI__builtin_add_nuw_nsw: { + bool NXW = BuiltinIDIfNoAsmLabel == Builtin::BI__builtin_add_nuw_nsw; + bool NUW = BuiltinIDIfNoAsmLabel == Builtin::BI__builtin_add_nuw || NXW; + bool NSW = BuiltinIDIfNoAsmLabel == Builtin::BI__builtin_add_nsw || NXW; llvm::Value *X = EmitScalarExpr(E->getArg(0)); llvm::Value *Y = EmitScalarExpr(E->getArg(1)); return RValue::get(Builder.CreateAdd(X, Y, "add", NUW, NSW)); diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 9cac9cf5c4df7..dc8526271237e 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -2105,6 +2105,34 @@ static bool BuiltinCountZeroBitsGeneric(Sema &S, CallExpr *TheCall) { return false; } +static bool BuiltinAddNoWrap(Sema &S, CallExpr *TheCall) { + if (S.checkArgCount(TheCall, 2)) + return true; + ExprResult OrigArg0 = TheCall->getArg(0); + ExprResult OrigArg1 = TheCall->getArg(1); + ExprResult Arg0 = OrigArg0; + ExprResult Arg1 = OrigArg1; + + QualType Res = S.UsualArithmeticConversions(Arg0, Arg1, TheCall->getExprLoc(), + Sema::ACK_Arithmetic); + if (Arg0.isInvalid() || Arg1.isInvalid()) + return true; + + if (Res.isNull() || !Res->isIntegralType(S.Context)) { + Expr *E0 = OrigArg0.get(); + Expr *E1 = OrigArg1.get(); + auto BadArg = !E0->getType()->isIntegralType(S.Context) ? E0 : E1; + return S.Diag(BadArg->getBeginLoc(), diag::err_builtin_add_nxw_invalid_arg) + << (BadArg == E0 ? 1 : 2) << BadArg->getType() + << BadArg->getSourceRange(); + } + + TheCall->setArg(0, Arg0.get()); + TheCall->setArg(1, Arg1.get()); + TheCall->setType(Res); + return false; +} + ExprResult Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, CallExpr *TheCall) { @@ -2975,6 +3003,12 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, if (BuiltinCountedByRef(TheCall)) return ExprError(); break; + case Builtin::BI__builtin_add_nuw: + case Builtin::BI__builtin_add_nsw: + case Builtin::BI__builtin_add_nuw_nsw: + if (BuiltinAddNoWrap(*this, TheCall)) + return ExprError(); + break; } if (getLangOpts().HLSL && HLSL().CheckBuiltinFunctionCall(BuiltinID, TheCall)) diff --git a/clang/test/CodeGen/builtins-int-wrap.c b/clang/test/CodeGen/builtins-int-wrap.c index 16eb92681fcc1..30f9de17869bc 100644 --- a/clang/test/CodeGen/builtins-int-wrap.c +++ b/clang/test/CodeGen/builtins-int-wrap.c @@ -5,107 +5,107 @@ //------------------------------------------------------------------------------ // int //------------------------------------------------------------------------------ -int test_sadd_nuw(int x, int y) { return __builtin_sadd_nuw(x, y); } -// CHECK-LABEL: @test_sadd_nuw +int test_add_nuw(int x, int y) { return __builtin_add_nuw(x, y); } +// CHECK-LABEL: @test_add_nuw // CHECK: [[RV:%.+]] = add nuw i32 // CHECK: ret i32 [[RV]] -int test_sadd_nsw(int x, int y) { return __builtin_sadd_nsw(x, y); } -// CHECK-LABEL: @test_sadd_nsw +int test_add_nsw(int x, int y) { return __builtin_add_nsw(x, y); } +// CHECK-LABEL: @test_add_nsw // CHECK: [[RV:%.+]] = add nsw i32 // CHECK: ret i32 [[RV]] -int test_sadd_nuw_nsw(int x, int y) { return __builtin_sadd_nuw_nsw(x, y); } -// CHECK-LABEL: @test_sadd_nuw_nsw +int test_add_nuw_nsw(int x, int y) { return __builtin_add_nuw_nsw(x, y); } +// CHECK-LABEL: @test_add_nuw_nsw // CHECK: [[RV:%.+]] = add nuw nsw i32 // CHECK: ret i32 [[RV]] //------------------------------------------------------------------------------ // long int //------------------------------------------------------------------------------ -long int test_saddl_nuw(long int x, long int y) { return __builtin_saddl_nuw(x, y); } -// CHECK-LABEL: @test_saddl_nuw +long int test_add_nuw_l(long int x, long int y) { return __builtin_add_nuw(x, y); } +// CHECK-LABEL: @test_add_nuw_l // CHECK: [[RV:%.+]] = add nuw i64 // CHECK: ret i64 [[RV]] -long int test_saddl_nsw(long int x, long int y) { return __builtin_saddl_nsw(x, y); } -// CHECK-LABEL: @test_saddl_nsw +long int test_add_nsw_l(long int x, long int y) { return __builtin_add_nsw(x, y); } +// CHECK-LABEL: @test_add_nsw_l // CHECK: [[RV:%.+]] = add nsw i64 // CHECK: ret i64 [[RV]] -long int test_saddl_nuw_nsw(long int x, long int y) { return __builtin_saddl_nuw_nsw(x, y); } -// CHECK-LABEL: @test_saddl_nuw_nsw +long int test_add_nuw_nsw_l(long int x, long int y) { return __builtin_add_nuw_nsw(x, y); } +// CHECK-LABEL: @test_add_nuw_nsw_l // CHECK: [[RV:%.+]] = add nuw nsw i64 // CHECK: ret i64 [[RV]] //------------------------------------------------------------------------------ // long int //------------------------------------------------------------------------------ -long long int test_saddll_nuw(long long int x, long long int y) { return __builtin_saddll_nuw(x, y); } -// CHECK-LABEL: @test_saddll_nuw +long long int test_add_nuw_ll(long long int x, long long int y) { return __builtin_add_nuw(x, y); } +// CHECK-LABEL: @test_add_nuw_ll // CHECK: [[RV:%.+]] = add nuw i64 // CHECK: ret i64 [[RV]] -long long int test_saddll_nsw(long long int x, long long int y) { return __builtin_saddll_nsw(x, y); } -// CHECK-LABEL: @test_saddll_nsw +long long int test_add_nsw_ll(long long int x, long long int y) { return __builtin_add_nsw(x, y); } +// CHECK-LABEL: @test_add_nsw_ll // CHECK: [[RV:%.+]] = add nsw i64 // CHECK: ret i64 [[RV]] -long long int test_saddll_nuw_nsw(long long int x, long long int y) { return __builtin_saddll_nuw_nsw(x, y); } -// CHECK-LABEL: @test_saddll_nuw_nsw +long long int test_add_nuw_nsw_ll(long long int x, long long int y) { return __builtin_add_nuw_nsw(x, y); } +// CHECK-LABEL: @test_add_nuw_nsw_ll // CHECK: [[RV:%.+]] = add nuw nsw i64 // CHECK: ret i64 [[RV]] //------------------------------------------------------------------------------ // unsigned int //------------------------------------------------------------------------------ -unsigned int test_uadd_nuw(unsigned int x, unsigned int y) { return __builtin_uadd_nuw(x, y); } -// CHECK-LABEL: @test_uadd_nuw +unsigned int test_add_nuw_u(unsigned int x, unsigned int y) { return __builtin_add_nuw(x, y); } +// CHECK-LABEL: @test_add_nuw_u // CHECK: [[RV:%.+]] = add nuw i32 // CHECK: ret i32 [[RV]] -unsigned int test_uadd_nsw(unsigned int x, unsigned int y) { return __builtin_uadd_nsw(x, y); } -// CHECK-LABEL: @test_uadd_nsw +unsigned int test_add_nsw_u(unsigned int x, unsigned int y) { return __builtin_add_nsw(x, y); } +// CHECK-LABEL: @test_add_nsw_u // CHECK: [[RV:%.+]] = add nsw i32 // CHECK: ret i32 [[RV]] -unsigned int test_uadd_nuw_nsw(unsigned int x, unsigned int y) { return __builtin_uadd_nuw_nsw(x, y); } -// CHECK-LABEL: @test_uadd_nuw_nsw +unsigned int test_add_nuw_nsw_u(unsigned int x, unsigned int y) { return __builtin_add_nuw_nsw(x, y); } +// CHECK-LABEL: @test_add_nuw_nsw_u // CHECK: [[RV:%.+]] = add nuw nsw i32 // CHECK: ret i32 [[RV]] //------------------------------------------------------------------------------ // unsigned long int //------------------------------------------------------------------------------ -unsigned long int test_uaddl_nuw(unsigned long int x, unsigned long int y) { return __builtin_uaddl_nuw(x, y); } -// CHECK-LABEL: @test_uaddl_nuw +unsigned long int test_add_nuw_ul(unsigned long int x, unsigned long int y) { return __builtin_add_nuw(x, y); } +// CHECK-LABEL: @test_add_nuw_ul // CHECK: [[RV:%.+]] = add nuw i64 // CHECK: ret i64 [[RV]] -unsigned long int test_uaddl_nsw(unsigned long int x, unsigned long int y) { return __builtin_uaddl_nsw(x, y); } -// CHECK-LABEL: @test_uaddl_nsw +unsigned long int test_add_nsw_ul(unsigned long int x, unsigned long int y) { return __builtin_add_nsw(x, y); } +// CHECK-LABEL: @test_add_nsw_ul // CHECK: [[RV:%.+]] = add nsw i64 // CHECK: ret i64 [[RV]] -unsigned long int test_uaddl_nuw_nsw(unsigned long int x, unsigned long int y) { return __builtin_uaddl_nuw_nsw(x, y); } -// CHECK-LABEL: @test_uaddl_nuw_nsw +unsigned long int test_add_nuw_nsw_ul(unsigned long int x, unsigned long int y) { return __builtin_add_nuw_nsw(x, y); } +// CHECK-LABEL: @test_add_nuw_nsw_ul // CHECK: [[RV:%.+]] = add nuw nsw i64 // CHECK: ret i64 [[RV]] //------------------------------------------------------------------------------ // unsigned long long int //------------------------------------------------------------------------------ -unsigned long long int test_uaddll_nuw(unsigned long long int x, unsigned long long int y) { return __builtin_uaddll_nuw(x, y); } -// CHECK-LABEL: @test_uaddll_nuw +unsigned long long int test_add_nuw_ull(unsigned long long int x, unsigned long long int y) { return __builtin_add_nuw(x, y); } +// CHECK-LABEL: @test_add_nuw_ull // CHECK: [[RV:%.+]] = add nuw i64 // CHECK: ret i64 [[RV]] -unsigned long long int test_uaddll_nsw(unsigned long long int x, unsigned long long int y) { return __builtin_uaddll_nsw(x, y); } -// CHECK-LABEL: @test_uaddll_nsw +unsigned long long int test_add_nsw_ull(unsigned long long int x, unsigned long long int y) { return __builtin_add_nsw(x, y); } +// CHECK-LABEL: @test_add_nsw_ull // CHECK: [[RV:%.+]] = add nsw i64 // CHECK: ret i64 [[RV]] -unsigned long long int test_uaddll_nuw_nsw(unsigned long long int x, unsigned long long int y) { return __builtin_uaddll_nuw_nsw(x, y); } -// CHECK-LABEL: @test_uaddll_nuw_nsw +unsigned long long int test_add_nuw_nsw_ull(unsigned long long int x, unsigned long long int y) { return __builtin_add_nuw_nsw(x, y); } +// CHECK-LABEL: @test_add_nuw_nsw_ull // CHECK: [[RV:%.+]] = add nuw nsw i64 // CHECK: ret i64 [[RV]] diff --git a/clang/test/Sema/builtins-int-wrap.c b/clang/test/Sema/builtins-int-wrap.c new file mode 100644 index 0000000000000..a59851ace3a97 --- /dev/null +++ b/clang/test/Sema/builtins-int-wrap.c @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64-unknown-unknown %s + + +struct Foo { int x; }; + +int test_add_nuw(int x, double y, struct Foo z) { + __builtin_add_nuw(x, y); // expected-error {{both arguments must be of integral type but 2nd argument is 'double'}} + __builtin_add_nuw(y, x); // expected-error {{both arguments must be of integral type but 1st argument is 'double'}} + __builtin_add_nuw(x, z); // expected-error {{both arguments must be of integral type but 2nd argument is 'struct Foo'}} +} + +int test_add_nsw(int x, double y, struct Foo z) { + __builtin_add_nsw(x, y); // expected-error {{both arguments must be of integral type but 2nd argument is 'double'}} + __builtin_add_nsw(y, x); // expected-error {{both arguments must be of integral type but 1st argument is 'double'}} + __builtin_add_nsw(x, z); // expected-error {{both arguments must be of integral type but 2nd argument is 'struct Foo'}} +} + +int test_add_nuw_nsw(int x, double y, struct Foo z) { + __builtin_add_nuw_nsw(x, y); // expected-error {{both arguments must be of integral type but 2nd argument is 'double'}} + __builtin_add_nuw_nsw(y, x); // expected-error {{both arguments must be of integral type but 1st argument is 'double'}} + __builtin_add_nuw_nsw(x, z); // expected-error {{both arguments must be of integral type but 2nd argument is 'struct Foo'}} +}