Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions clang/include/clang/Basic/TargetInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,10 @@ struct TransferrableTargetInfo {
/// zero length bitfield, regardless of the zero length bitfield type.
unsigned ZeroLengthBitfieldBoundary;

/// The largest container size which should be used for an over-sized
/// bitfield, in bits.
unsigned LargestOverSizedBitfieldContainer;

/// If non-zero, specifies a maximum alignment to truncate alignment
/// specified in the aligned attribute of a static variable to this value.
unsigned MaxAlignedAttribute;
Expand Down Expand Up @@ -954,6 +958,10 @@ class TargetInfo : public TransferrableTargetInfo,
return ZeroLengthBitfieldBoundary;
}

unsigned getLargestOverSizedBitfieldContainer() const {
return LargestOverSizedBitfieldContainer;
}

/// Get the maximum alignment in bits for a static variable with
/// aligned attribute.
unsigned getMaxAlignedAttribute() const { return MaxAlignedAttribute; }
Expand Down
10 changes: 7 additions & 3 deletions clang/lib/AST/RecordLayoutBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1469,15 +1469,18 @@ void ItaniumRecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize,
// sizeof(T')*8 <= n.

QualType IntegralPODTypes[] = {
Context.UnsignedCharTy, Context.UnsignedShortTy, Context.UnsignedIntTy,
Context.UnsignedLongTy, Context.UnsignedLongLongTy
Context.UnsignedCharTy, Context.UnsignedShortTy,
Context.UnsignedIntTy, Context.UnsignedLongTy,
Context.UnsignedLongLongTy, Context.UnsignedInt128Ty,
};

QualType Type;
uint64_t MaxSize =
Context.getTargetInfo().getLargestOverSizedBitfieldContainer();
for (const QualType &QT : IntegralPODTypes) {
uint64_t Size = Context.getTypeSize(QT);

if (Size > FieldSize)
if (Size > FieldSize || Size > MaxSize)
break;

Type = QT;
Expand Down Expand Up @@ -1520,6 +1523,7 @@ void ItaniumRecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize,
setSize(std::max(getSizeInBits(), getDataSizeInBits()));

// Remember max struct/class alignment.
UnadjustedAlignment = std::max(UnadjustedAlignment, TypeAlign);
UpdateAlignment(TypeAlign);
}

Expand Down
1 change: 1 addition & 0 deletions clang/lib/Basic/TargetInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ TargetInfo::TargetInfo(const llvm::Triple &T) : Triple(T) {
UseLeadingZeroLengthBitfield = true;
UseExplicitBitFieldAlignment = true;
ZeroLengthBitfieldBoundary = 0;
LargestOverSizedBitfieldContainer = 64;
MaxAlignedAttribute = 0;
HalfFormat = &llvm::APFloat::IEEEhalf();
FloatFormat = &llvm::APFloat::IEEEsingle();
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Basic/Targets/AArch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,10 @@ AArch64TargetInfo::AArch64TargetInfo(const llvm::Triple &Triple,
assert(UseBitFieldTypeAlignment && "bitfields affect type alignment");
UseZeroLengthBitfieldAlignment = true;

// AAPCS64 allows any "fundamental integer data type" to be used for
// over-sized bitfields, which includes 128-bit integers.
LargestOverSizedBitfieldContainer = 128;

HasUnalignedAccess = true;

// AArch64 targets default to using the ARM C++ ABI.
Expand Down
43 changes: 43 additions & 0 deletions clang/test/CodeGen/aapcs-align.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@

extern "C" {

// CHECK: @sizeof_OverSizedBitfield ={{.*}} global i32 8
// CHECK: @alignof_OverSizedBitfield ={{.*}} global i32 8
// CHECK: @sizeof_VeryOverSizedBitfield ={{.*}} global i32 16
// CHECK: @alignof_VeryOverSizedBitfield ={{.*}} global i32 8

// Base case, nothing interesting.
struct S {
int x, y;
Expand Down Expand Up @@ -138,4 +143,42 @@ void g6() {
// CHECK: call void @f6m(i32 noundef 1, i32 noundef 2, i32 noundef 3, i32 noundef 4, i32 noundef 5, [4 x i32] [i32 6, i32 7, i32 0, i32 undef])
// CHECK: declare void @f6(i32 noundef, [4 x i32])
// CHECK: declare void @f6m(i32 noundef, i32 noundef, i32 noundef, i32 noundef, i32 noundef, [4 x i32])

// Over-sized bitfield, which results in a 64-bit container type, so 64-bit
// alignment.
struct OverSizedBitfield {
int x : 64;
};

unsigned sizeof_OverSizedBitfield = sizeof(OverSizedBitfield);
unsigned alignof_OverSizedBitfield = alignof(OverSizedBitfield);

// CHECK: define{{.*}} void @g7
// CHECK: call void @f7(i32 noundef 1, [1 x i64] [i64 42])
// CHECK: declare void @f7(i32 noundef, [1 x i64])
void f7(int a, OverSizedBitfield b);
void g7() {
OverSizedBitfield s = {42};
f7(1, s);
}

// There are no 128-bit fundamental data types defined by AAPCS32, so this gets
// a 64-bit container plus 64 bits of padding, giving it a size of 16 bytes and
// alignment of 8 bytes.
struct VeryOverSizedBitfield {
int x : 128;
};

unsigned sizeof_VeryOverSizedBitfield = sizeof(VeryOverSizedBitfield);
unsigned alignof_VeryOverSizedBitfield = alignof(VeryOverSizedBitfield);

// CHECK: define{{.*}} void @g8
// CHECK: call void @f8(i32 noundef 1, [2 x i64] [i64 42, i64 0])
// CHECK: declare void @f8(i32 noundef, [2 x i64])
void f8(int a, VeryOverSizedBitfield b);
void g8() {
VeryOverSizedBitfield s = {42};
f8(1, s);
}

}
64 changes: 64 additions & 0 deletions clang/test/CodeGen/aapcs64-align.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@

extern "C" {

// CHECK: @sizeof_OverSizedBitfield ={{.*}} global i32 8
// CHECK: @alignof_OverSizedBitfield ={{.*}} global i32 8
// CHECK: @sizeof_VeryOverSizedBitfield ={{.*}} global i32 16
// CHECK: @alignof_VeryOverSizedBitfield ={{.*}} global i32 16
// CHECK: @sizeof_RidiculouslyOverSizedBitfield ={{.*}} global i32 32
// CHECK: @alignof_RidiculouslyOverSizedBitfield ={{.*}} global i32 16

// Base case, nothing interesting.
struct S {
long x, y;
Expand Down Expand Up @@ -161,5 +168,62 @@ int test_bitint8(){
}
// CHECK: ret i32 1

// Over-sized bitfield, which results in a 64-bit container type, so 64-bit
// alignment.
struct OverSizedBitfield {
int x : 64;
};

unsigned sizeof_OverSizedBitfield = sizeof(OverSizedBitfield);
unsigned alignof_OverSizedBitfield = alignof(OverSizedBitfield);

// CHECK: define{{.*}} void @g7
// CHECK: call void @f7(i32 noundef 1, i64 42)
// CHECK: declare void @f7(i32 noundef, i64)
void f7(int a, OverSizedBitfield b);
void g7() {
OverSizedBitfield s = {42};
f7(1, s);
}

// There are no 128-bit fundamental data types defined by AAPCS32, so this gets
// a 64-bit container plus 64 bits of padding, giving it a size of 16 bytes and
// alignment of 8 bytes.
struct VeryOverSizedBitfield {
int x : 128;
};

unsigned sizeof_VeryOverSizedBitfield = sizeof(VeryOverSizedBitfield);
unsigned alignof_VeryOverSizedBitfield = alignof(VeryOverSizedBitfield);

// CHECK: define{{.*}} void @g8
// CHECK: call void @f8(i32 noundef 1, i128 42)
// CHECK: declare void @f8(i32 noundef, i128)
void f8(int a, VeryOverSizedBitfield b);
void g8() {
VeryOverSizedBitfield s = {42};
f8(1, s);
}

// There are no bigger fundamental data types, so this gets a 128-bit container
// and 128 bits of padding, giving the struct a size of 32 bytes, and an
// alignment of 16 bytes. This is over the PCS size limit of 16 bytes, so it
// will be passed indirectly.
struct RidiculouslyOverSizedBitfield {
int x : 256;
};

unsigned sizeof_RidiculouslyOverSizedBitfield = sizeof(RidiculouslyOverSizedBitfield);
unsigned alignof_RidiculouslyOverSizedBitfield = alignof(RidiculouslyOverSizedBitfield);

// CHECK: define{{.*}} void @g9
// CHECK: call void @f9(i32 noundef 1, ptr noundef nonnull %agg.tmp)
// CHECK: declare void @f9(i32 noundef, ptr noundef)
void f9(int a, RidiculouslyOverSizedBitfield b);
void g9() {
RidiculouslyOverSizedBitfield s = {42};
f9(1, s);
}

}

Original file line number Diff line number Diff line change
Expand Up @@ -248,8 +248,8 @@ struct S15 {
};

// CHECK-LABEL: define dso_local void @_Z4fS15v
// CHECK: alloca %struct.S15, align 8
// CHECK-NEXT: [[TMP0:%.*]] = alloca %struct.S15, align 8
// CHECK: alloca %struct.S15, align 16
// CHECK-NEXT: [[TMP0:%.*]] = alloca %struct.S15, align 16
// CHECK: #dbg_declare(ptr [[TMP0]], [[S15_A:![0-9]+]], !DIExpression(DW_OP_LLVM_extract_bits_sext, 0, 32),
// CHECK-NEXT: #dbg_declare(ptr [[TMP0]], [[S15_B:![0-9]+]], !DIExpression(DW_OP_plus_uconst, 16, DW_OP_LLVM_extract_bits_zext, 0, 32),
//
Expand Down