summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Y Knight <jyknight@google.com>2015-08-21 18:19:06 +0000
committerJames Y Knight <jyknight@google.com>2015-08-21 18:19:06 +0000
commit7160857da377e50d42b7d892844428c78338c696 (patch)
treea9f77aaa231eb3e173ae96e05b9c708eba858a64
parent1e3dc527ea6d548bd776896d6fe73a91754d762e (diff)
downloadbcm5719-llvm-7160857da377e50d42b7d892844428c78338c696.tar.gz
bcm5719-llvm-7160857da377e50d42b7d892844428c78338c696.zip
Properly provide alignment of 'byval' arguments down to llvm.
This is important in the case that the LLVM-inferred llvm-struct alignment is not the same as the clang-known C-struct alignment. Differential Revision: http://reviews.llvm.org/D12243 llvm-svn: 245719
-rw-r--r--clang/lib/CodeGen/CGCall.cpp21
-rw-r--r--clang/test/CodeGen/le32-arguments.c6
-rw-r--r--clang/test/CodeGen/nvptx-abi.c10
-rw-r--r--clang/test/CodeGen/sparc-arguments.c27
4 files changed, 53 insertions, 11 deletions
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index a5802346d4a..f40dd086481 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -1663,20 +1663,35 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
Attrs.addAttribute(llvm::Attribute::InReg);
break;
- case ABIArgInfo::Indirect:
+ case ABIArgInfo::Indirect: {
if (AI.getInReg())
Attrs.addAttribute(llvm::Attribute::InReg);
if (AI.getIndirectByVal())
Attrs.addAttribute(llvm::Attribute::ByVal);
- Attrs.addAlignmentAttr(AI.getIndirectAlign());
+ unsigned Align = AI.getIndirectAlign();
+
+ // In a byval argument, it is important that the required
+ // alignment of the type is honored, as LLVM might be creating a
+ // *new* stack object, and needs to know what alignment to give
+ // it. (Sometimes it can deduce a sensible alignment on its own,
+ // but not if clang decides it must emit a packed struct, or the
+ // user specifies increased alignment requirements.)
+ //
+ // This is different from indirect *not* byval, where the object
+ // exists already, and the align attribute is purely
+ // informative.
+ if (Align == 0 && AI.getIndirectByVal())
+ Align = getContext().getTypeAlignInChars(ParamType).getQuantity();
+
+ Attrs.addAlignmentAttr(Align);
// byval disables readnone and readonly.
FuncAttrs.removeAttribute(llvm::Attribute::ReadOnly)
.removeAttribute(llvm::Attribute::ReadNone);
break;
-
+ }
case ABIArgInfo::Ignore:
case ABIArgInfo::Expand:
continue;
diff --git a/clang/test/CodeGen/le32-arguments.c b/clang/test/CodeGen/le32-arguments.c
index d26640e6927..e81d84387d3 100644
--- a/clang/test/CodeGen/le32-arguments.c
+++ b/clang/test/CodeGen/le32-arguments.c
@@ -10,7 +10,7 @@ typedef struct {
int bb;
} s1;
// Structs should be passed byval and not split up
-// CHECK-LABEL: define void @f1(%struct.s1* byval %i)
+// CHECK-LABEL: define void @f1(%struct.s1* byval align 4 %i)
void f1(s1 i) {}
typedef struct {
@@ -48,7 +48,7 @@ union simple_union {
char b;
};
// Unions should be passed as byval structs
-// CHECK-LABEL: define void @f7(%union.simple_union* byval %s)
+// CHECK-LABEL: define void @f7(%union.simple_union* byval align 4 %s)
void f7(union simple_union s) {}
typedef struct {
@@ -57,5 +57,5 @@ typedef struct {
int b8 : 8;
} bitfield1;
// Bitfields should be passed as byval structs
-// CHECK-LABEL: define void @f8(%struct.bitfield1* byval %bf1)
+// CHECK-LABEL: define void @f8(%struct.bitfield1* byval align 4 %bf1)
void f8(bitfield1 bf1) {}
diff --git a/clang/test/CodeGen/nvptx-abi.c b/clang/test/CodeGen/nvptx-abi.c
index 58ad6a17f24..7973bf06533 100644
--- a/clang/test/CodeGen/nvptx-abi.c
+++ b/clang/test/CodeGen/nvptx-abi.c
@@ -21,14 +21,14 @@ float bar(void) {
void foo(float4_t x) {
// CHECK-LABEL: @foo
-// CHECK: %struct.float4_s* byval %x
+// CHECK: %struct.float4_s* byval align 4 %x
}
void fooN(float4_t x, float4_t y, float4_t z) {
// CHECK-LABEL: @fooN
-// CHECK: %struct.float4_s* byval %x
-// CHECK: %struct.float4_s* byval %y
-// CHECK: %struct.float4_s* byval %z
+// CHECK: %struct.float4_s* byval align 4 %x
+// CHECK: %struct.float4_s* byval align 4 %y
+// CHECK: %struct.float4_s* byval align 4 %z
}
typedef struct nested_s {
@@ -39,5 +39,5 @@ typedef struct nested_s {
void baz(nested_t x) {
// CHECK-LABEL: @baz
-// CHECK: %struct.nested_s* byval %x)
+// CHECK: %struct.nested_s* byval align 8 %x)
}
diff --git a/clang/test/CodeGen/sparc-arguments.c b/clang/test/CodeGen/sparc-arguments.c
new file mode 100644
index 00000000000..c86b40b11fb
--- /dev/null
+++ b/clang/test/CodeGen/sparc-arguments.c
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -triple sparc-unknown-unknown -emit-llvm -o - %s | FileCheck %s
+
+// Ensure that we pass proper alignment to llvm in the call
+// instruction. The proper alignment for the type is sometimes known
+// only by clang, and is not manifest in the LLVM-type. So, it must be
+// explicitly passed through. (Besides the case of the user specifying
+// alignment, as here, this situation also occurrs for non-POD C++
+// structs with tail-padding: clang emits these as packed llvm-structs
+// for ABI reasons.)
+
+struct s1 {
+ int x;
+} __attribute__((aligned(8)));
+
+struct s1 x1;
+
+
+// Ensure the align 8 is passed through:
+// CHECK-LABEL: define void @f1()
+// CHECK: call void @f1_helper(%struct.s1* byval align 8 @x1)
+// Also ensure the declaration of f1_helper includes it
+// CHECK: declare void @f1_helper(%struct.s1* byval align 8)
+
+void f1_helper(struct s1);
+void f1() {
+ f1_helper(x1);
+}
OpenPOWER on IntegriCloud