Index: docs/LanguageExtensions.rst =================================================================== --- docs/LanguageExtensions.rst +++ docs/LanguageExtensions.rst @@ -1224,8 +1224,9 @@ Clang supports a number of builtin library functions with the same syntax as GCC, including things like ``__builtin_nan``, ``__builtin_constant_p``, ``__builtin_choose_expr``, ``__builtin_types_compatible_p``, -``__sync_fetch_and_add``, etc. In addition to the GCC builtins, Clang supports -a number of builtins that GCC does not, which are listed here. +``__builtin_assume_aligned``, ``__sync_fetch_and_add``, etc. In addition to +the GCC builtins, Clang supports a number of builtins that GCC does not, which +are listed here. Please note that Clang does not and will not support all of the GCC builtins for vector operations. Instead of using builtins, you should use the functions @@ -1235,6 +1236,41 @@ ` instead of builtins, in order to reduce the number of builtins that we need to implement. +``__builtin_assume`` +------------------------------ + +``__builtin_assume`` is used to provide the optimizer with a boolean +invariant that is defined to be true. + +**Syntax**: + +.. code-block:: c++ + + __builtin_assume(bool) + +**Example of Use**: + +.. code-block:: c++ + + int foo(int x) { + __builtin_assume(x != 0); + + // The optimizer may short-circuit this check using the invariant. + if (x == 0) + return do_something(); + + return do_something_else(); + } + +**Description**: + +The boolean argument to this function is defined to be true. The optimizer may +analyze the expression used to compute the argument and deduce from that +information used to optimize the program. If the condition is violated during +execution, the behavior is undefined. + +Query for this feature with ``__has_builtin(__builtin_assume)``. + ``__builtin_readcyclecounter`` ------------------------------ Index: include/clang/Basic/Builtins.def =================================================================== --- include/clang/Basic/Builtins.def +++ include/clang/Basic/Builtins.def @@ -412,6 +412,7 @@ BUILTIN(__builtin_va_end, "vA", "n") BUILTIN(__builtin_va_copy, "vAA", "n") BUILTIN(__builtin_stdarg_start, "vA.", "n") +BUILTIN(__builtin_assume_aligned, "v*vC*z.", "nc") BUILTIN(__builtin_bcmp, "iv*v*z", "n") BUILTIN(__builtin_bcopy, "vv*v*z", "n") BUILTIN(__builtin_bzero, "vv*z", "nF") @@ -1173,6 +1174,9 @@ // Annotation function BUILTIN(__builtin_annotation, "v.", "tn") +// Invariants +BUILTIN(__builtin_assume, "vb", "n") + // Multiprecision Arithmetic Builtins. BUILTIN(__builtin_addcb, "UcUcCUcCUcCUc*", "n") BUILTIN(__builtin_addcs, "UsUsCUsCUsCUs*", "n") Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -8244,6 +8244,7 @@ private: bool SemaBuiltinPrefetch(CallExpr *TheCall); + bool SemaBuiltinAssumeAligned(CallExpr *TheCall); bool SemaBuiltinLongjmp(CallExpr *TheCall); ExprResult SemaBuiltinAtomicOverloaded(ExprResult TheCallResult); ExprResult SemaAtomicOpsOverloaded(ExprResult TheCallResult, Index: lib/AST/ExprConstant.cpp =================================================================== --- lib/AST/ExprConstant.cpp +++ lib/AST/ExprConstant.cpp @@ -6086,6 +6086,7 @@ return Success(Operand, E); } + case Builtin::BI__builtin_assume_aligned: case Builtin::BI__builtin_expect: return Visit(E->getArg(0)); Index: lib/CodeGen/CGBuiltin.cpp =================================================================== --- lib/CodeGen/CGBuiltin.cpp +++ lib/CodeGen/CGBuiltin.cpp @@ -388,6 +388,39 @@ "expval"); return RValue::get(Result); } + case Builtin::BI__builtin_assume_aligned: { + Value *PtrValue = EmitScalarExpr(E->getArg(0)); + Value *PtrIntValue = + Builder.CreatePtrToInt(PtrValue, IntPtrTy, "ptrint"); + + Value *AlignmentValue = EmitScalarExpr(E->getArg(1)); + ConstantInt *AlignmentCI = cast(AlignmentValue); + unsigned Alignment = (unsigned) AlignmentCI->getZExtValue(); + + Value *Mask = llvm::ConstantInt::get(IntPtrTy, + Alignment > 0 ? Alignment - 1 : 0); + if (E->getNumArgs() > 2) { + Value *OffsetValue = EmitScalarExpr(E->getArg(2)); + if (OffsetValue->getType() != IntPtrTy) + OffsetValue = Builder.CreateIntCast(OffsetValue, IntPtrTy, + /*isSigned*/true, "offsetcast"); + PtrIntValue = Builder.CreateSub(PtrIntValue, OffsetValue, "offsetptr"); + } + + Value *Zero = llvm::ConstantInt::get(IntPtrTy, 0); + Value *MaskedPtr = Builder.CreateAnd(PtrIntValue, Mask, "maskedptr"); + Value *InvCond = Builder.CreateICmpEQ(MaskedPtr, Zero, "maskcond"); + + Value *FnInvariant = CGM.getIntrinsic(Intrinsic::invariant); + Builder.CreateCall(FnInvariant, InvCond); + return RValue::get(PtrValue); + } + case Builtin::BI__assume: + case Builtin::BI__builtin_assume: { + Value *ArgValue = EmitScalarExpr(E->getArg(0)); + Value *FnInvariant = CGM.getIntrinsic(Intrinsic::invariant); + return RValue::get(Builder.CreateCall(FnInvariant, ArgValue)); + } case Builtin::BI__builtin_bswap16: case Builtin::BI__builtin_bswap32: case Builtin::BI__builtin_bswap64: { Index: lib/Sema/SemaChecking.cpp =================================================================== --- lib/Sema/SemaChecking.cpp +++ lib/Sema/SemaChecking.cpp @@ -35,6 +35,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallBitVector.h" #include "llvm/ADT/SmallString.h" +#include "llvm/IR/Value.h" #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/raw_ostream.h" #include @@ -175,6 +176,10 @@ if (SemaBuiltinPrefetch(TheCall)) return ExprError(); break; + case Builtin::BI__builtin_assume_aligned: + if (SemaBuiltinAssumeAligned(TheCall)) + return ExprError(); + break; case Builtin::BI__builtin_object_size: if (SemaBuiltinConstantArgRange(TheCall, 1, 0, 3)) return ExprError(); @@ -1942,6 +1947,51 @@ return false; } +/// Handle __builtin_assume_aligned. This is declared +/// as (const void*, size_t, ...) and can take one optional constant int arg. +bool Sema::SemaBuiltinAssumeAligned(CallExpr *TheCall) { + unsigned NumArgs = TheCall->getNumArgs(); + + if (NumArgs > 3) + return Diag(TheCall->getLocEnd(), + diag::err_typecheck_call_too_many_args_at_most) + << 0 /*function call*/ << 3 << NumArgs + << TheCall->getSourceRange(); + + // Argument 0 is checked for us; the alignment must be a constant integer. + Expr *Arg = TheCall->getArg(1); + + // We can't check the value of a dependent argument. + if (!Arg->isTypeDependent() && !Arg->isValueDependent()) { + llvm::APSInt Result; + if (SemaBuiltinConstantArg(TheCall, 1, Result)) + return true; + + if (Result.getLimitedValue() > +llvm::Value::MaximumAlignment || + !Result.isUnsigned()) + return Diag(TheCall->getLocStart(), diag::err_argument_invalid_range) + << "0" << +llvm::Value::MaximumAlignment << Arg->getSourceRange(); + if (!Result.isPowerOf2()) + return Diag(TheCall->getLocStart(), + diag::err_attribute_aligned_not_power_of_two) + << Arg->getSourceRange(); + } + + if (NumArgs > 2) { + Arg = TheCall->getArg(2); + QualType T = Arg->getType(); + + // Note: gcc specifies the prototype as taking a size_t, but LLVM can + // handle only 32-bit alignment values. + if (!T->isIntegralType(Context)) + return Diag(TheCall->getLocStart(), + diag::err_typecheck_converted_constant_expression) + << T << "an integral type" << Arg->getSourceRange(); + } + + return false; +} + /// SemaBuiltinConstantArg - Handle a check if argument ArgNum of CallExpr /// TheCall is a constant expression. bool Sema::SemaBuiltinConstantArg(CallExpr *TheCall, int ArgNum, Index: test/CodeGen/builtin-assume-aligned.c =================================================================== --- /dev/null +++ test/CodeGen/builtin-assume-aligned.c @@ -0,0 +1,46 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck %s + +// CHECK: @test1 +int test1(int *a) { +// CHECK: %ptrint = ptrtoint +// CHECK: %offsetptr = sub i64 %ptrint, 0 +// CHECK: %maskedptr = and i64 %offsetptr, 31 +// CHECK: %maskcond = icmp eq i64 %maskedptr, 0 +// CHECK: call void @llvm.invariant(i1 %maskcond) + a = __builtin_assume_aligned(a, 32, 0ull); + return a[0]; +} + +// CHECK: @test2 +int test2(int *a) { +// CHECK: %ptrint = ptrtoint +// CHECK: %offsetptr = sub i64 %ptrint, 0 +// CHECK: %maskedptr = and i64 %offsetptr, 31 +// CHECK: %maskcond = icmp eq i64 %maskedptr, 0 +// CHECK: call void @llvm.invariant(i1 %maskcond) + a = __builtin_assume_aligned(a, 32, 0); + return a[0]; +} + +// CHECK: @test3 +int test3(int *a) { +// CHECK: %ptrint = ptrtoint +// CHECK: %maskedptr = and i64 %ptrint, 31 +// CHECK: %maskcond = icmp eq i64 %maskedptr, 0 +// CHECK: call void @llvm.invariant(i1 %maskcond) + a = __builtin_assume_aligned(a, 32); + return a[0]; +} + +// CHECK: @test4 +int test4(int *a, int b) { +// CHECK: %ptrint = ptrtoint +// CHECK: %offsetcast = sext i32 +// CHECK: %offsetptr = sub i64 %ptrint, %offsetcast +// CHECK: %maskedptr = and i64 %offsetptr, 31 +// CHECK: %maskcond = icmp eq i64 %maskedptr, 0 +// CHECK: call void @llvm.invariant(i1 %maskcond) + a = __builtin_assume_aligned(a, 32, b); + return a[0]; +} + Index: test/CodeGen/builtin-assume.c =================================================================== --- /dev/null +++ test/CodeGen/builtin-assume.c @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple i386-mingw32 -fms-extensions -emit-llvm -o - %s | FileCheck %s + +// CHECK: @test1 +int test1(int *a) { +// CHECK: %0 = load i32** %a.addr +// CHECK: %cmp = icmp ne i32* %0, null +// CHECK: call void @llvm.invariant(i1 %cmp) +#ifdef _MSC_VER + __assume(a != 0) +#else + __builtin_assume(a != 0); +#endif + return a[0]; +} + Index: test/Sema/builtin-assume-aligned-tmpl.cpp =================================================================== --- /dev/null +++ test/Sema/builtin-assume-aligned-tmpl.cpp @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +template +int test9(int *a) { + a = (int *) __builtin_assume_aligned(a, z + 1); // expected-error {{requested alignment is not a power of 2}} + return a[0]; +} + +void test9i(int *a) { + test9<42>(a); // expected-note {{in instantiation of function template specialization 'test9<42>' requested here}} +} + +template +int test10(int *a, T z) { + a = (int *) __builtin_assume_aligned(a, z + 1); // expected-error {{must be a constant integer}} + return a[0]; +} + +int test10i(int *a) { + return test10(a, 42); // expected-note {{in instantiation of function template specialization 'test10' requested here}} +} + Index: test/Sema/builtin-assume-aligned.c =================================================================== --- /dev/null +++ test/Sema/builtin-assume-aligned.c @@ -0,0 +1,43 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +int test1(int *a) { + a = __builtin_assume_aligned(a, 32, 0ull); + return a[0]; +} + +int test2(int *a) { + a = __builtin_assume_aligned(a, 32, 0); + return a[0]; +} + +int test3(int *a) { + a = __builtin_assume_aligned(a, 32); + return a[0]; +} + +int test4(int *a) { + a = __builtin_assume_aligned(a, -32); // expected-error {{argument should be a value from 0 to 536870912}} + a = __builtin_assume_aligned(a, 1ULL << 63); // expected-error {{argument should be a value from 0 to 536870912}} + return a[0]; +} + +int test5(int *a, unsigned *b) { + a = __builtin_assume_aligned(a, 32, b); // expected-error {{value of type 'unsigned int *' is not implicitly convertible to an integral type}} + return a[0]; +} + +int test6(int *a) { + a = __builtin_assume_aligned(a, 32, 0, 0); // expected-error {{too many arguments to function call, expected at most 3, have 4}} + return a[0]; +} + +int test7(int *a) { + a = __builtin_assume_aligned(a, 31); // expected-error {{requested alignment is not a power of 2}} + return a[0]; +} + +int test8(int *a, int j) { + a = __builtin_assume_aligned(a, j); // expected-error {{must be a constant integer}} + return a[0]; +} +