mirror of
https://github.com/intel/llvm.git
synced 2026-02-08 08:57:43 +08:00
When building constant structs, check if the resulting LLVM struct will be bigger than the record layout size and use a packed struct if that's the case. Fixes PR5108.
llvm-svn: 83230
This commit is contained in:
@@ -37,10 +37,13 @@ class VISIBILITY_HIDDEN ConstStructBuilder {
|
||||
|
||||
unsigned NextFieldOffsetInBytes;
|
||||
|
||||
unsigned LLVMStructAlignment;
|
||||
|
||||
std::vector<llvm::Constant *> Elements;
|
||||
|
||||
ConstStructBuilder(CodeGenModule &CGM, CodeGenFunction *CGF)
|
||||
: CGM(CGM), CGF(CGF), Packed(false), NextFieldOffsetInBytes(0) { }
|
||||
: CGM(CGM), CGF(CGF), Packed(false), NextFieldOffsetInBytes(0),
|
||||
LLVMStructAlignment(1) { }
|
||||
|
||||
bool AppendField(const FieldDecl *Field, uint64_t FieldOffset,
|
||||
const Expr *InitExpr) {
|
||||
@@ -61,44 +64,11 @@ class VISIBILITY_HIDDEN ConstStructBuilder {
|
||||
llvm::RoundUpToAlignment(NextFieldOffsetInBytes, FieldAlignment);
|
||||
|
||||
if (AlignedNextFieldOffsetInBytes > FieldOffsetInBytes) {
|
||||
std::vector<llvm::Constant *> PackedElements;
|
||||
|
||||
assert(!Packed && "Alignment is wrong even with a packed struct!");
|
||||
|
||||
// Convert the struct to a packed struct.
|
||||
uint64_t ElementOffsetInBytes = 0;
|
||||
|
||||
for (unsigned i = 0, e = Elements.size(); i != e; ++i) {
|
||||
llvm::Constant *C = Elements[i];
|
||||
|
||||
unsigned ElementAlign =
|
||||
CGM.getTargetData().getABITypeAlignment(C->getType());
|
||||
uint64_t AlignedElementOffsetInBytes =
|
||||
llvm::RoundUpToAlignment(ElementOffsetInBytes, ElementAlign);
|
||||
|
||||
if (AlignedElementOffsetInBytes > ElementOffsetInBytes) {
|
||||
// We need some padding.
|
||||
uint64_t NumBytes =
|
||||
AlignedElementOffsetInBytes - ElementOffsetInBytes;
|
||||
|
||||
const llvm::Type *Ty = llvm::Type::getInt8Ty(CGF->getLLVMContext());
|
||||
if (NumBytes > 1)
|
||||
Ty = llvm::ArrayType::get(Ty, NumBytes);
|
||||
|
||||
llvm::Constant *Padding = llvm::Constant::getNullValue(Ty);
|
||||
PackedElements.push_back(Padding);
|
||||
ElementOffsetInBytes += getSizeInBytes(Padding);
|
||||
}
|
||||
|
||||
PackedElements.push_back(C);
|
||||
ElementOffsetInBytes += getSizeInBytes(C);
|
||||
}
|
||||
|
||||
assert(ElementOffsetInBytes == NextFieldOffsetInBytes &&
|
||||
"Packing the struct changed its size!");
|
||||
|
||||
Elements = PackedElements;
|
||||
Packed = true;
|
||||
ConvertStructToPacked();
|
||||
|
||||
AlignedNextFieldOffsetInBytes = NextFieldOffsetInBytes;
|
||||
}
|
||||
|
||||
@@ -115,7 +85,7 @@ class VISIBILITY_HIDDEN ConstStructBuilder {
|
||||
// Add the field.
|
||||
Elements.push_back(C);
|
||||
NextFieldOffsetInBytes = AlignedNextFieldOffsetInBytes + getSizeInBytes(C);
|
||||
|
||||
LLVMStructAlignment = std::max(LLVMStructAlignment, FieldAlignment);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -270,6 +240,44 @@ class VISIBILITY_HIDDEN ConstStructBuilder {
|
||||
AppendPadding(NumPadBytes);
|
||||
}
|
||||
|
||||
void ConvertStructToPacked() {
|
||||
std::vector<llvm::Constant *> PackedElements;
|
||||
uint64_t ElementOffsetInBytes = 0;
|
||||
|
||||
for (unsigned i = 0, e = Elements.size(); i != e; ++i) {
|
||||
llvm::Constant *C = Elements[i];
|
||||
|
||||
unsigned ElementAlign =
|
||||
CGM.getTargetData().getABITypeAlignment(C->getType());
|
||||
uint64_t AlignedElementOffsetInBytes =
|
||||
llvm::RoundUpToAlignment(ElementOffsetInBytes, ElementAlign);
|
||||
|
||||
if (AlignedElementOffsetInBytes > ElementOffsetInBytes) {
|
||||
// We need some padding.
|
||||
uint64_t NumBytes =
|
||||
AlignedElementOffsetInBytes - ElementOffsetInBytes;
|
||||
|
||||
const llvm::Type *Ty = llvm::Type::getInt8Ty(CGF->getLLVMContext());
|
||||
if (NumBytes > 1)
|
||||
Ty = llvm::ArrayType::get(Ty, NumBytes);
|
||||
|
||||
llvm::Constant *Padding = llvm::Constant::getNullValue(Ty);
|
||||
PackedElements.push_back(Padding);
|
||||
ElementOffsetInBytes += getSizeInBytes(Padding);
|
||||
}
|
||||
|
||||
PackedElements.push_back(C);
|
||||
ElementOffsetInBytes += getSizeInBytes(C);
|
||||
}
|
||||
|
||||
assert(ElementOffsetInBytes == NextFieldOffsetInBytes &&
|
||||
"Packing the struct changed its size!");
|
||||
|
||||
Elements = PackedElements;
|
||||
LLVMStructAlignment = 1;
|
||||
Packed = true;
|
||||
}
|
||||
|
||||
bool Build(InitListExpr *ILE) {
|
||||
RecordDecl *RD = ILE->getType()->getAs<RecordType>()->getDecl();
|
||||
const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
|
||||
@@ -306,11 +314,24 @@ class VISIBILITY_HIDDEN ConstStructBuilder {
|
||||
// we must have a flexible array member at the end.
|
||||
assert(RD->hasFlexibleArrayMember() &&
|
||||
"Must have flexible array member if struct is bigger than type!");
|
||||
|
||||
|
||||
// No tail padding is necessary.
|
||||
return true;
|
||||
}
|
||||
|
||||
uint64_t LLVMSizeInBytes = llvm::RoundUpToAlignment(NextFieldOffsetInBytes,
|
||||
LLVMStructAlignment);
|
||||
|
||||
// Check if we need to convert the struct to a packed struct.
|
||||
if (NextFieldOffsetInBytes <= LayoutSizeInBytes &&
|
||||
LLVMSizeInBytes > LayoutSizeInBytes) {
|
||||
assert(!Packed && "Size mismatch!");
|
||||
|
||||
ConvertStructToPacked();
|
||||
assert(NextFieldOffsetInBytes == LayoutSizeInBytes &&
|
||||
"Converting to packed did not help!");
|
||||
}
|
||||
|
||||
// Append tail padding if necessary.
|
||||
AppendTailPadding(Layout.getSize());
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// RUN: clang-cc -triple i386-pc-linux-gnu -verify -emit-llvm -o %t %s &&
|
||||
// RUN: clang-cc -triple i386-pc-linux-gnu -verify -emit-llvm -o %t %s | FileCheck %s --input-file=%t &&
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
@@ -47,6 +47,12 @@ int g9 = (2 + 3i) * (5 + 7i) != (-11 + 29i);
|
||||
// RUN: grep '@g10 = global i32 0' %t &&
|
||||
int g10 = (2.0 + 3.0i) * (5.0 + 7.0i) != (-11.0 + 29.0i);
|
||||
|
||||
// PR5108
|
||||
// CHECK: @ss = global %4 <{ i32 0, i8 7 }>, align 1
|
||||
struct s {
|
||||
unsigned long a;
|
||||
unsigned long b:3;
|
||||
} __attribute__((__packed__)) ss = { .a = 0x0, .b = 7, };
|
||||
|
||||
// Global references
|
||||
// RUN: grep '@g11.l0 = internal global i32 ptrtoint (i32 ()\* @g11 to i32)' %t &&
|
||||
|
||||
Reference in New Issue
Block a user