https://github.com/macurtis-amd created https://github.com/llvm/llvm-project/pull/130354
To be used for OpenMP runtime library development where lack of control over nuw/nsw prevents analysis by ScalarEvolution and subsequently loop unrolling. >From 57c81a241f75d7d5d92d727038aa5851096ac18d Mon Sep 17 00:00:00 2001 From: Matthew Curtis <macur...@amd.com> Date: Fri, 7 Mar 2025 11:16:28 -0600 Subject: [PATCH] [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 b86bb242755be..227cffe8ae2f7 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]] _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits