Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions clang/include/clang/Basic/Builtins.td
Original file line number Diff line number Diff line change
Expand Up @@ -5037,6 +5037,24 @@ def ArithmeticFence : LangBuiltin<"ALL_LANGUAGES"> {
let Prototype = "void(...)";
}

def AddNUW : Builtin {
let Spellings = ["__builtin_add_nuw"];
let Attributes = [CustomTypeChecking, NoThrow];
let Prototype = "void(...)";
}

def AddNSW : Builtin {
let Spellings = ["__builtin_add_nsw"];
let Attributes = [CustomTypeChecking, NoThrow];
let Prototype = "void(...)";
}

def AddNW : Builtin {
let Spellings = ["__builtin_add_nuw_nsw"];
let Attributes = [CustomTypeChecking, NoThrow];
let Prototype = "void(...)";
}

def CountedByRef : Builtin {
let Spellings = ["__builtin_counted_by_ref"];
let Attributes = [NoThrow, CustomTypeChecking];
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -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">,
Expand Down
11 changes: 11 additions & 0 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6616,6 +6616,17 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
auto Str = CGM.GetAddrOfConstantCString(Name, "");
return RValue::get(Str.getPointer());
}

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));
}
}

// If this is an alias for a lib function (e.g. __builtin_sin), emit
Expand Down
34 changes: 34 additions & 0 deletions clang/lib/Sema/SemaChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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))
Expand Down
111 changes: 111 additions & 0 deletions clang/test/CodeGen/builtins-int-wrap.c
Original file line number Diff line number Diff line change
@@ -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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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]]
22 changes: 22 additions & 0 deletions clang/test/Sema/builtins-int-wrap.c
Original file line number Diff line number Diff line change
@@ -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'}}
}
Loading