forked from OSchip/llvm-project
Add support for __builtin_alloca_with_align
__builtin_alloca always uses __BIGGEST_ALIGNMENT__ for the alignment of the allocation. __builtin_alloca_with_align allows the programmer to specify the alignment of the allocation. This fixes PR30658. llvm-svn: 285544
This commit is contained in:
parent
dc586c4ee4
commit
5116993f8e
|
@ -512,6 +512,7 @@ BUILTIN(__builtin_unreachable, "v", "nr")
|
|||
BUILTIN(__builtin_shufflevector, "v." , "nc")
|
||||
BUILTIN(__builtin_convertvector, "v." , "nct")
|
||||
BUILTIN(__builtin_alloca, "v*z" , "Fn")
|
||||
BUILTIN(__builtin_alloca_with_align, "v*zIz", "Fn")
|
||||
BUILTIN(__builtin_call_with_static_chain, "v.", "nt")
|
||||
|
||||
// "Overloaded" Atomic operator builtins. These are overloaded to support data
|
||||
|
|
|
@ -2440,6 +2440,10 @@ def err_no_accessor_for_property : Error<
|
|||
def error_cannot_find_suitable_accessor : Error<
|
||||
"cannot find suitable %select{getter|setter}0 for property %1">;
|
||||
|
||||
def err_alignment_too_small : Error<
|
||||
"requested alignment must be %0 or greater">;
|
||||
def err_alignment_too_big : Error<
|
||||
"requested alignment must be %0 or smaller">;
|
||||
def err_alignment_not_power_of_two : Error<
|
||||
"requested alignment is not a power of 2">;
|
||||
def err_alignment_dependent_typedef_name : Error<
|
||||
|
|
|
@ -9719,6 +9719,7 @@ public:
|
|||
|
||||
private:
|
||||
bool SemaBuiltinPrefetch(CallExpr *TheCall);
|
||||
bool SemaBuiltinAllocaWithAlign(CallExpr *TheCall);
|
||||
bool SemaBuiltinAssume(CallExpr *TheCall);
|
||||
bool SemaBuiltinAssumeAligned(CallExpr *TheCall);
|
||||
bool SemaBuiltinLongjmp(CallExpr *TheCall);
|
||||
|
|
|
@ -1147,6 +1147,19 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
|
|||
AI->setAlignment(SuitableAlignmentInBytes);
|
||||
return RValue::get(AI);
|
||||
}
|
||||
|
||||
case Builtin::BI__builtin_alloca_with_align: {
|
||||
Value *Size = EmitScalarExpr(E->getArg(0));
|
||||
Value *AlignmentValue = EmitScalarExpr(E->getArg(1));
|
||||
auto *AlignmentCI = cast<ConstantInt>(AlignmentValue);
|
||||
unsigned Alignment = AlignmentCI->getZExtValue();
|
||||
const TargetInfo &TI = getContext().getTargetInfo();
|
||||
unsigned AlignmentInBytes = Alignment / TI.getCharWidth();
|
||||
AllocaInst *AI = Builder.CreateAlloca(Builder.getInt8Ty(), Size);
|
||||
AI->setAlignment(AlignmentInBytes);
|
||||
return RValue::get(AI);
|
||||
}
|
||||
|
||||
case Builtin::BIbzero:
|
||||
case Builtin::BI__builtin_bzero: {
|
||||
Address Dest = EmitPointerWithAlignment(E->getArg(0));
|
||||
|
|
|
@ -791,6 +791,10 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
|
|||
if (SemaBuiltinPrefetch(TheCall))
|
||||
return ExprError();
|
||||
break;
|
||||
case Builtin::BI__builtin_alloca_with_align:
|
||||
if (SemaBuiltinAllocaWithAlign(TheCall))
|
||||
return ExprError();
|
||||
break;
|
||||
case Builtin::BI__assume:
|
||||
case Builtin::BI__builtin_assume:
|
||||
if (SemaBuiltinAssume(TheCall))
|
||||
|
@ -3903,6 +3907,36 @@ bool Sema::SemaBuiltinAssume(CallExpr *TheCall) {
|
|||
return false;
|
||||
}
|
||||
|
||||
/// Handle __builtin_assume_aligned. This is declared
|
||||
/// as (size_t, size_t) where the second size_t must be a power of 2 greater
|
||||
/// than 8.
|
||||
bool Sema::SemaBuiltinAllocaWithAlign(CallExpr *TheCall) {
|
||||
// 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 = Arg->EvaluateKnownConstInt(Context);
|
||||
|
||||
if (!Result.isPowerOf2())
|
||||
return Diag(TheCall->getLocStart(),
|
||||
diag::err_alignment_not_power_of_two)
|
||||
<< Arg->getSourceRange();
|
||||
|
||||
if (Result < Context.getCharWidth())
|
||||
return Diag(TheCall->getLocStart(), diag::err_alignment_too_small)
|
||||
<< (unsigned)Context.getCharWidth()
|
||||
<< Arg->getSourceRange();
|
||||
|
||||
if (Result > INT32_MAX)
|
||||
return Diag(TheCall->getLocStart(), diag::err_alignment_too_big)
|
||||
<< INT32_MAX
|
||||
<< Arg->getSourceRange();
|
||||
}
|
||||
|
||||
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) {
|
||||
|
|
|
@ -55,6 +55,7 @@ bool BuiltinFunctionChecker::evalCall(const CallExpr *CE,
|
|||
return true;
|
||||
}
|
||||
|
||||
case Builtin::BI__builtin_alloca_with_align:
|
||||
case Builtin::BI__builtin_alloca: {
|
||||
// FIXME: Refactor into StoreManager itself?
|
||||
MemRegionManager& RM = C.getStoreManager().getRegionManager();
|
||||
|
|
|
@ -43,6 +43,7 @@ public:
|
|||
void CheckReallocZero(CheckerContext &C, const CallExpr *CE) const;
|
||||
void CheckReallocfZero(CheckerContext &C, const CallExpr *CE) const;
|
||||
void CheckAllocaZero(CheckerContext &C, const CallExpr *CE) const;
|
||||
void CheckAllocaWithAlignZero(CheckerContext &C, const CallExpr *CE) const;
|
||||
void CheckVallocZero(CheckerContext &C, const CallExpr *CE) const;
|
||||
|
||||
typedef void (UnixAPIChecker::*SubChecker)(CheckerContext &,
|
||||
|
@ -337,6 +338,11 @@ void UnixAPIChecker::CheckAllocaZero(CheckerContext &C,
|
|||
BasicAllocationCheck(C, CE, 1, 0, "alloca");
|
||||
}
|
||||
|
||||
void UnixAPIChecker::CheckAllocaWithAlignZero(CheckerContext &C,
|
||||
const CallExpr *CE) const {
|
||||
BasicAllocationCheck(C, CE, 2, 0, "__builtin_alloca_with_align");
|
||||
}
|
||||
|
||||
void UnixAPIChecker::CheckVallocZero(CheckerContext &C,
|
||||
const CallExpr *CE) const {
|
||||
BasicAllocationCheck(C, CE, 1, 0, "valloc");
|
||||
|
@ -366,6 +372,8 @@ void UnixAPIChecker::checkPreStmt(const CallExpr *CE,
|
|||
.Case("realloc", &UnixAPIChecker::CheckReallocZero)
|
||||
.Case("reallocf", &UnixAPIChecker::CheckReallocfZero)
|
||||
.Cases("alloca", "__builtin_alloca", &UnixAPIChecker::CheckAllocaZero)
|
||||
.Case("__builtin_alloca_with_align",
|
||||
&UnixAPIChecker::CheckAllocaWithAlignZero)
|
||||
.Case("valloc", &UnixAPIChecker::CheckVallocZero)
|
||||
.Default(nullptr);
|
||||
|
||||
|
|
|
@ -1,9 +1,16 @@
|
|||
// RUN: %clang_cc1 %s -emit-llvm -o - -fms-extensions -triple i686-pc-win32 | FileCheck %s
|
||||
|
||||
// CHECK-LABEL: define void @test_alloca
|
||||
// CHECK-LABEL: define void @test_alloca(
|
||||
void capture(void *);
|
||||
void test_alloca(int n) {
|
||||
capture(_alloca(n));
|
||||
// CHECK: %[[arg:.*]] = alloca i8, i32 %{{.*}}, align 16
|
||||
// CHECK: call void @capture(i8* %[[arg]])
|
||||
}
|
||||
|
||||
// CHECK-LABEL: define void @test_alloca_with_align(
|
||||
void test_alloca_with_align(int n) {
|
||||
capture(__builtin_alloca_with_align(n, 64));
|
||||
// CHECK: %[[arg:.*]] = alloca i8, i32 %{{.*}}, align 8
|
||||
// CHECK: call void @capture(i8* %[[arg]])
|
||||
}
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -verify %s
|
||||
|
||||
void test1(int a) {
|
||||
__builtin_alloca_with_align(a, 32);
|
||||
}
|
||||
|
||||
void test2(int a) {
|
||||
__builtin_alloca_with_align(a, -32); // expected-error {{requested alignment is not a power of 2}}
|
||||
}
|
||||
|
||||
void test3(unsigned *b) {
|
||||
__builtin_alloca_with_align(b, 32); // expected-warning {{incompatible pointer to integer conversion passing 'unsigned int *' to parameter of type}}
|
||||
}
|
||||
|
||||
void test4(int a) {
|
||||
__builtin_alloca_with_align(a, 32, 0); // expected-error {{too many arguments to function call, expected 2, have 3}}
|
||||
}
|
||||
|
||||
void test5(int a) {
|
||||
__builtin_alloca_with_align(a, 31); // expected-error {{requested alignment is not a power of 2}}
|
||||
}
|
||||
|
||||
void test6(int a, int j) {
|
||||
__builtin_alloca_with_align(a, j); // expected-error {{must be a constant integer}}
|
||||
}
|
||||
|
||||
void test7(int a) {
|
||||
__builtin_alloca_with_align(a, 2); // expected-error {{requested alignment must be 8 or greater}}
|
||||
}
|
Loading…
Reference in New Issue