]> granicus.if.org Git - clang/commitdiff
Add support for __builtin_alloca_with_align
authorDavid Majnemer <david.majnemer@gmail.com>
Mon, 31 Oct 2016 05:37:48 +0000 (05:37 +0000)
committerDavid Majnemer <david.majnemer@gmail.com>
Mon, 31 Oct 2016 05:37:48 +0000 (05:37 +0000)
__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.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@285544 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/Builtins.def
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Sema/Sema.h
lib/CodeGen/CGBuiltin.cpp
lib/Sema/SemaChecking.cpp
lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
test/CodeGen/builtins-ms.c
test/Sema/builtin-alloca-with-align.c [new file with mode: 0644]

index 8d2746ba9ced86b049f01537d00410d0509a01fd..de5332c444616705454de88a864129c75578fc93 100644 (file)
@@ -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
index 9d375c7239d1b96cd3d6735076fb5592e0f5cbce..085008753f9acff33e9c0d7cc77286bd694e9d45 100644 (file)
@@ -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<
index 3507a8a2351b5255b5c4a6b9e35231d4bb3c009d..0ad20123cc0057720bec2ddd40534fd66fe59a90 100644 (file)
@@ -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);
index c73a6e1b061ed696e1f6f79408376b7c6e17bf48..54566aa7e519885e4e7db866bb6d55e854974d33 100644 (file)
@@ -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));
index c73bd4c6ed23e93a55696bf13f1c6f610cde04ab..a4e3c5b8b24cd9094c0cfce342eed5fbb34ab116 100644 (file)
@@ -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) {
index dab2f61229a0a847194d566b38f0faf99e927a35..8c2aef21b3cabe913ff6fd80403d7858ba14ad05 100644 (file)
@@ -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();
index 4b78c2058341968c3daa2531900c1b60ef82f530..c9dafb518c4d31b462d4a96f3273740b8d658d1c 100644 (file)
@@ -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);
 
index 31c0331c56d2c05d6fbd1c6737ec69a75d951a12..a33b57de8ddf8bb34d905195f913c2b678fcb9bd 100644 (file)
@@ -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]])
+}
diff --git a/test/Sema/builtin-alloca-with-align.c b/test/Sema/builtin-alloca-with-align.c
new file mode 100644 (file)
index 0000000..67dc09d
--- /dev/null
@@ -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}}
+}