Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix insufficient alignment of BaseBitcastABIRewrite allocas #3698

Merged
merged 1 commit into from
Apr 17, 2021
Merged
Show file tree
Hide file tree
Changes from all 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
30 changes: 18 additions & 12 deletions gen/abi-generic.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,25 +123,29 @@ struct RemoveStructPadding : ABIRewrite {
* the bit-cast.
*/
struct BaseBitcastABIRewrite : ABIRewrite {
static unsigned getMaxAlignment(LLType *llType, Type *dType) {
return std::max(getABITypeAlign(llType), DtoAlignment(dType));
}

LLValue *put(DValue *dv, bool, bool) override {
LLValue *address = dv->isLVal() ? DtoLVal(dv) : nullptr;
LLType *asType = type(dv->type);
const unsigned alignment = getMaxAlignment(asType, dv->type);
const char *name = ".BaseBitcastABIRewrite_arg";

if (!address) {
address = DtoAllocaDump(dv, asType, 0, ".BaseBitcastABIRewrite_arg_storage");
if (!dv->isLVal()) {
LLValue *dump = DtoAllocaDump(dv, asType, alignment,
".BaseBitcastABIRewrite_arg_storage");
return DtoLoad(dump, name);
}

LLValue *address = DtoLVal(dv);
LLType *pointeeType = address->getType()->getPointerElementType();

if (asType == pointeeType) {
return DtoLoad(address, name);
}

if (getTypeStoreSize(asType) > getTypeAllocSize(pointeeType)) {
// not enough allocated memory
LLValue *paddedDump =
DtoRawAlloca(asType, 0, ".BaseBitcastABIRewrite_padded_arg_storage");
if (getTypeStoreSize(asType) > getTypeAllocSize(pointeeType) ||
alignment > DtoAlignment(dv->type)) {
// not enough allocated memory or insufficiently aligned
LLValue *paddedDump = DtoRawAlloca(
asType, alignment, ".BaseBitcastABIRewrite_padded_arg_storage");
DtoMemCpy(paddedDump, address,
DtoConstSize_t(getTypeAllocSize(pointeeType)));
return DtoLoad(paddedDump, name);
Expand All @@ -152,7 +156,9 @@ struct BaseBitcastABIRewrite : ABIRewrite {
}

LLValue *getLVal(Type *dty, LLValue *v) override {
return DtoAllocaDump(v, dty, ".BaseBitcastABIRewrite_param_storage");
const unsigned alignment = getMaxAlignment(v->getType(), dty);
return DtoAllocaDump(v, DtoType(dty), alignment,
".BaseBitcastABIRewrite_param_storage");
}

void applyToIfNotObsolete(IrFuncTyArg &arg, LLType *finalLType = nullptr) {
Expand Down
47 changes: 47 additions & 0 deletions tests/codegen/gh3692.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// https://github.com/ldc-developers/ldc/issues/3692

// REQUIRES: target_X86
// RUN: %ldc -mtriple=x86_64-linux-gnu -output-ll -of=%t.ll %s
// RUN: FileCheck %s < %t.ll


// D `int[3]` rewritten to LL `{ i64, i32 }` for SysV ABI - mismatching size and alignment
// CHECK: define void @_D6gh36924takeFG3iZv({ i64, i32 } %a_arg)
void take(int[3] a)
{
// the `{ i64, i32 }` size is 16 bytes, so we need a padded alloca (with 8-bytes alignment)
// CHECK-NEXT: %.BaseBitcastABIRewrite_param_storage = alloca { i64, i32 }, align 8
// CHECK-NEXT: store { i64, i32 } %a_arg, { i64, i32 }* %.BaseBitcastABIRewrite_param_storage
// CHECK-NEXT: %a = bitcast { i64, i32 }* %.BaseBitcastABIRewrite_param_storage to [3 x i32]*
}

// CHECK: define void @_D6gh36924passFZv()
void pass()
{
// CHECK-NEXT: %arrayliteral = alloca [3 x i32], align 4
// we need an extra padded alloca with proper alignment
// CHECK-NEXT: %.BaseBitcastABIRewrite_padded_arg_storage = alloca { i64, i32 }, align 8
// CHECK: %.BaseBitcastABIRewrite_arg = load { i64, i32 }, { i64, i32 }* %.BaseBitcastABIRewrite_padded_arg_storage
take([1, 2, 3]);
}


// D `int[4]` rewritten to LL `{ i64, i64 }` for SysV ABI - mismatching alignment only
// CHECK: define void @_D6gh36925take4FG4iZv({ i64, i64 } %a_arg)
void take4(int[4] a)
{
// the alloca should have 8-bytes alignment, even though a.alignof == 4
// CHECK-NEXT: %a = alloca [4 x i32], align 8
// CHECK-NEXT: %1 = bitcast [4 x i32]* %a to { i64, i64 }*
// CHECK-NEXT: store { i64, i64 } %a_arg, { i64, i64 }* %1
}

// CHECK: define void @_D6gh36925pass4FZv()
void pass4()
{
// CHECK-NEXT: %arrayliteral = alloca [4 x i32], align 4
// we need an extra alloca with 8-bytes alignment
// CHECK-NEXT: %.BaseBitcastABIRewrite_padded_arg_storage = alloca { i64, i64 }, align 8
// CHECK: %.BaseBitcastABIRewrite_arg = load { i64, i64 }, { i64, i64 }* %.BaseBitcastABIRewrite_padded_arg_storage
take4([1, 2, 3, 4]);
}