Index: include/clang/Basic/Builtins.def =================================================================== --- include/clang/Basic/Builtins.def +++ include/clang/Basic/Builtins.def @@ -402,6 +402,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") Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -7189,6 +7189,7 @@ private: bool SemaBuiltinPrefetch(CallExpr *TheCall); + bool SemaBuiltinAssumeAligned(CallExpr *TheCall); bool SemaBuiltinObjectSize(CallExpr *TheCall); bool SemaBuiltinLongjmp(CallExpr *TheCall); ExprResult SemaBuiltinAtomicOverloaded(ExprResult TheCallResult); Index: lib/AST/ExprConstant.cpp =================================================================== --- lib/AST/ExprConstant.cpp +++ lib/AST/ExprConstant.cpp @@ -4313,6 +4313,7 @@ } case Builtin::BI__builtin_expect: + case Builtin::BI__builtin_assume_aligned: return Visit(E->getArg(0)); case Builtin::BIstrlen: Index: lib/CodeGen/CGBuiltin.cpp =================================================================== --- lib/CodeGen/CGBuiltin.cpp +++ lib/CodeGen/CGBuiltin.cpp @@ -354,6 +354,26 @@ "expval"); return RValue::get(Result); } + case Builtin::BI__builtin_assume_aligned: { + Value *ArgValue = EmitScalarExpr(E->getArg(0)); + + Value *AlignmentValue = EmitScalarExpr(E->getArg(1)); + AlignmentValue = Builder.CreateIntCast(AlignmentValue, Int32Ty, false); + + Value *OffsetValue = (E->getNumArgs() > 2) ? EmitScalarExpr(E->getArg(2)) : + llvm::ConstantInt::get(Int32Ty, 0); + + llvm::SmallVector Types; + Types.push_back(ArgValue->getType()); + Types.push_back(OffsetValue->getType()); + + Value *FnAssumeAligned = + CGM.getIntrinsic(Intrinsic::assume_aligned, Types); + + Value *Result = Builder.CreateCall3(FnAssumeAligned, ArgValue, + AlignmentValue, OffsetValue, "alignedval"); + return RValue::get(Result); + } 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 @@ -159,6 +159,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 (SemaBuiltinObjectSize(TheCall)) return ExprError(); @@ -1582,6 +1586,52 @@ return false; } +/// Handle __builtin_assume_aligned. +// This is declared to take (const void*, size_t, ...) and can take one +// optional constant int args. +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.isIntN(32) || !Result.isUnsigned()) + return Diag(TheCall->getLocStart(), diag::err_argument_invalid_range) + << "0" << "2147483648" << 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,23 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck %s + +// CHECK: @test1 +int test1(int *a) { +// CHECK: @llvm.assume.aligned.p0i8.i64 + a = __builtin_assume_aligned(a, 32, 0ull); + return a[0]; +} + +// CHECK: @test2 +int test2(int *a) { +// CHECK: @llvm.assume.aligned.p0i8.i32 + a = __builtin_assume_aligned(a, 32, 0); + return a[0]; +} + +// CHECK: @test3 +int test3(int *a) { +// CHECK: @llvm.assume.aligned.p0i8.i32 + a = __builtin_assume_aligned(a, 32); + return a[0]; +} + Index: test/Sema/builtin-assume-aligned.c =================================================================== --- /dev/null +++ test/Sema/builtin-assume-aligned.c @@ -0,0 +1,27 @@ +// 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}} + return a[0]; +} + +int test5(int *a, unsigned *b) { + a = __builtin_assume_aligned(a, 32, b); // expected-error {{is not implicitly convertible to an integral type}} + return a[0]; +} +