rnk created this revision.
rnk added a reviewer: rsmith.
rnk added a subscriber: cfe-commits.
GCC documents that the alignment parameter is in bits and it must be:
- an integer constant
- a power of two
- a multiple of CHAR_BITS
- below an unspecified limit
This lines up directly with the requirements for LLVM's alloca
instruction, so I went ahead and wired it up. We limit the alignment to
1<<29, which is the maximum alignment supported by LLVM's alloca.
Implements feature request in PR30658
https://reviews.llvm.org/D25581
Files:
include/clang/Basic/Builtins.def
include/clang/Basic/DiagnosticSemaKinds.td
lib/CodeGen/CGBuiltin.cpp
lib/Sema/SemaChecking.cpp
test/CodeGen/alloca.c
test/Sema/builtin-alloca.c
Index: test/Sema/builtin-alloca.c
===================================================================
--- /dev/null
+++ test/Sema/builtin-alloca.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 %s -verify -triple=x86_64-linux
+
+void aligned_alloca(__SIZE_TYPE__ n) {
+ __builtin_alloca_with_align(n, n); // expected-error {{argument to '__builtin_alloca_with_align' must be a constant integer}}
+ __builtin_alloca_with_align(n, 3); // expected-error {{requested alignment is not a power of 2}}
+ __builtin_alloca_with_align(n, 4); // expected-error {{requested bit alignment is not a multiple of CHAR_WIDTH}}
+ __builtin_alloca_with_align(n, 8ULL<<30); // expected-error {{requested alignment must be 536870912 bytes or smaller}}
+ __builtin_alloca_with_align(n, 8);
+ __builtin_alloca_with_align(n, 64);
+ __builtin_alloca_with_align(n, 128);
+ __builtin_alloca_with_align(n, 4096);
+}
Index: test/CodeGen/alloca.c
===================================================================
--- test/CodeGen/alloca.c
+++ test/CodeGen/alloca.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
+// RUN: %clang_cc1 -triple x86_64-linux -emit-llvm %s -o - | FileCheck %s
typedef __SIZE_TYPE__ size_t;
void *alloca(size_t size);
@@ -9,3 +9,21 @@
strcpy(C, argv[0]);
puts(C);
}
+
+// CHECK-LABEL: define i32 @main
+// CHECK: alloca i8, i64 %{{.*}}
+// CHECK: call i8* @strcpy
+
+
+void aligned_alloca(size_t n) {
+ __builtin_alloca_with_align(n, 8);
+ __builtin_alloca_with_align(n, 64);
+ __builtin_alloca_with_align(n, 128);
+ __builtin_alloca_with_align(n, 4096);
+}
+
+// CHECK-LABEL: define void @aligned_alloca
+// CHECK: alloca i8, i64 %{{[^,]*}}, align 1
+// CHECK: alloca i8, i64 %{{[^,]*}}, align 8
+// CHECK: alloca i8, i64 %{{[^,]*}}, align 16
+// CHECK: alloca i8, i64 %{{[^,]*}}, align 512
Index: lib/Sema/SemaChecking.cpp
===================================================================
--- lib/Sema/SemaChecking.cpp
+++ lib/Sema/SemaChecking.cpp
@@ -966,6 +966,28 @@
DeclareGlobalNewDelete();
break;
+ case Builtin::BI__builtin_alloca_with_align: {
+ llvm::APSInt AlignAP;
+ bool AlignIsConst = TheCall->getArg(1)->EvaluateAsInt(AlignAP, Context);
+ assert(AlignIsConst && "basic checking failed");
+ // Keep this in sync with llvm::Value::MaximumAlignment.
+ unsigned MaxAlignBytes = 1U << 29;
+ if (!AlignAP.isPowerOf2()) {
+ Diag(TheCall->getExprLoc(), diag::err_alignment_not_power_of_two);
+ return ExprError();
+ }
+ if (AlignAP > MaxAlignBytes * 8ULL) {
+ Diag(TheCall->getExprLoc(), diag::err_attribute_aligned_too_great)
+ << MaxAlignBytes;
+ return ExprError();
+ }
+ if (AlignAP.getZExtValue() % Context.getCharWidth() != 0) {
+ Diag(TheCall->getExprLoc(), diag::err_alignment_not_char_width);
+ return ExprError();
+ }
+ break;
+ }
+
// check secure string manipulation functions where overflows
// are detectable at compile time
case Builtin::BI__builtin___memcpy_chk:
Index: lib/CodeGen/CGBuiltin.cpp
===================================================================
--- lib/CodeGen/CGBuiltin.cpp
+++ lib/CodeGen/CGBuiltin.cpp
@@ -1027,6 +1027,21 @@
Value *Size = EmitScalarExpr(E->getArg(0));
return RValue::get(Builder.CreateAlloca(Builder.getInt8Ty(), Size));
}
+ case Builtin::BI__builtin_alloca_with_align: {
+ // FIXME: The GCC docs say that the "lifetime of the allocated object ends
+ // at the end of the block in which the function was called", but "the
+ // allocated storage is released no later than just before the calling
+ // function returns to its caller". Our implementation behaves like a normal
+ // alloca, which releases the allocated memory on function return.
+ Value *Size = EmitScalarExpr(E->getArg(0));
+ llvm::APSInt AlignInBits;
+ if (!E->getArg(1)->EvaluateAsInt(AlignInBits, CGM.getContext()))
+ break;
+ unsigned Align =
+ AlignInBits.getZExtValue() / CGM.getContext().getCharWidth();
+ return RValue::get(
+ Builder.Insert(new AllocaInst(Builder.getInt8Ty(), Size, Align)));
+ }
case Builtin::BIbzero:
case Builtin::BI__builtin_bzero: {
Address Dest = EmitPointerWithAlignment(E->getArg(0));
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -2429,6 +2429,8 @@
"requested alignment is not a power of 2">;
def err_alignment_dependent_typedef_name : Error<
"requested alignment is dependent but declaration is not dependent">;
+def err_alignment_not_char_width : Error<
+ "requested bit alignment is not a multiple of CHAR_WIDTH">;
def err_attribute_aligned_too_great : Error<
"requested alignment must be %0 bytes or smaller">;
Index: include/clang/Basic/Builtins.def
===================================================================
--- include/clang/Basic/Builtins.def
+++ include/clang/Basic/Builtins.def
@@ -512,6 +512,7 @@
BUILTIN(__builtin_shufflevector, "v." , "nc")
BUILTIN(__builtin_convertvector, "v." , "nct")
BUILTIN(__builtin_alloca, "v*z" , "Fn")
+BUILTIN(__builtin_alloca_with_align, "v*zIz", "n")
BUILTIN(__builtin_call_with_static_chain, "v.", "nt")
// "Overloaded" Atomic operator builtins. These are overloaded to support data
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits