So I finally came up with a way to fix the alignment issue.
Please review the attached patch & test case.
The idea is to add a parameter to ABIArgInfo::getDirect that is used to set the
size of a padding inserted before a byval aggregate. The test case shows
padding is inserted before the first element of a 16-byte aligned byval
structure when the first element is not aligned to a 16-byte boundary.
________________________________________
From: Eli Friedman [[email protected]]
Sent: Monday, November 07, 2011 8:04 PM
To: Hatanaka, Akira
Cc: [email protected]
Subject: Re: [cfe-commits] r143596 - /cfe/trunk/lib/CodeGen/TargetInfo.cpp
On Mon, Nov 7, 2011 at 7:27 PM, Hatanaka, Akira <[email protected]> wrote:
> Just to add to my previous email,
>
> tail call void @callee(i32 3, double %0, i64 %1, i64 %2, i64 %3) nounwind
>
> Without alignment information attached to "double %0", this is how the
> backend will pass arguments in registers, when the function above is lowered:
> i32 3 => 1st integer register
> double %0 => 2nd FP register
> i64 %1 => 3rd integer register
> i64 %2, i64 %3 => 4th and 5th integer register
>
> The correct way to pass arguments is the following:
> i32 3 => 1st integer register
> double %0 => 3rd FP register
> i64 %1 => 4th integer register
> i64 %2, i64 %3 => 5th and 6th integer register
As you've figured out, you can't attach alignment to scalars. IIRC,
x86 doesn't run into this issue. Something like "tail call void
@callee(i32 3, i32 undef, double %0, i64 %1, i64 %2, i64 %3) nounwind"
probably does what you want. I'm not entirely sure how you would
convince clang to emit that, though; it might require extending the
ABI interface a bit.
-Eli
// RUN: %clang_cc1 -emit-llvm %s -o /dev/null
/* Regression test. Just compile .c -> .ll to test */
int foo(void) {
unsigned char *pp;
unsigned w_cnt;
w_cnt += *pp;
return w_cnt;
}
Index: lib/CodeGen/ABIInfo.h
===================================================================
--- lib/CodeGen/ABIInfo.h (revision 147536)
+++ lib/CodeGen/ABIInfo.h (working copy)
@@ -69,19 +69,22 @@
private:
Kind TheKind;
llvm::Type *TypeData;
- unsigned UIntData;
+ unsigned UIntData0;
+ unsigned UIntData1;
bool BoolData0;
bool BoolData1;
- ABIArgInfo(Kind K, llvm::Type *TD=0,
- unsigned UI=0, bool B0 = false, bool B1 = false)
- : TheKind(K), TypeData(TD), UIntData(UI), BoolData0(B0), BoolData1(B1) {}
+ ABIArgInfo(Kind K, llvm::Type *TD=0, unsigned UI0=0, unsigned UI1=0,
+ bool B0 = false, bool B1 = false)
+ : TheKind(K), TypeData(TD), UIntData0(UI0), UIntData1(UI1), BoolData0(B0),
+ BoolData1(B1) {}
public:
- ABIArgInfo() : TheKind(Direct), TypeData(0), UIntData(0) {}
+ ABIArgInfo() : TheKind(Direct), TypeData(0), UIntData0(0), UIntData1(0) {}
- static ABIArgInfo getDirect(llvm::Type *T = 0, unsigned Offset = 0) {
- return ABIArgInfo(Direct, T, Offset);
+ static ABIArgInfo getDirect(llvm::Type *T = 0, unsigned Offset = 0,
+ unsigned PaddingSize = 0) {
+ return ABIArgInfo(Direct, T, Offset, PaddingSize);
}
static ABIArgInfo getExtend(llvm::Type *T = 0) {
return ABIArgInfo(Extend, T, 0);
@@ -91,7 +94,7 @@
}
static ABIArgInfo getIndirect(unsigned Alignment, bool ByVal = true
, bool Realign = false) {
- return ABIArgInfo(Indirect, 0, Alignment, ByVal, Realign);
+ return ABIArgInfo(Indirect, 0, Alignment, 0, ByVal, Realign);
}
static ABIArgInfo getExpand() {
return ABIArgInfo(Expand);
@@ -111,8 +114,14 @@
// Direct/Extend accessors
unsigned getDirectOffset() const {
assert((isDirect() || isExtend()) && "Not a direct or extend kind");
- return UIntData;
+ return UIntData0;
}
+
+ unsigned getPaddingSize() const {
+ assert(isDirect() && "Not a direct kind");
+ return UIntData1;
+ }
+
llvm::Type *getCoerceToType() const {
assert(canHaveCoerceToType() && "Invalid kind!");
return TypeData;
@@ -126,7 +135,7 @@
// Indirect accessors
unsigned getIndirectAlign() const {
assert(TheKind == Indirect && "Invalid kind!");
- return UIntData;
+ return UIntData0;
}
bool getIndirectByVal() const {
Index: lib/CodeGen/TargetInfo.cpp
===================================================================
--- lib/CodeGen/TargetInfo.cpp (revision 147536)
+++ lib/CodeGen/TargetInfo.cpp (working copy)
@@ -3047,7 +3047,7 @@
ABIInfo(CGT), IsO32(_IsO32), MinABIStackAlignInBytes(IsO32 ? 4 : 8) {}
ABIArgInfo classifyReturnType(QualType RetTy) const;
- ABIArgInfo classifyArgumentType(QualType RetTy) const;
+ ABIArgInfo classifyArgumentType(QualType RetTy, uint64_t &Offset) const;
virtual void computeInfo(CGFunctionInfo &FI) const;
virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
CodeGenFunction &CGF) const;
@@ -3132,28 +3132,40 @@
return llvm::StructType::get(getVMContext(), ArgList);
}
-ABIArgInfo MipsABIInfo::classifyArgumentType(QualType Ty) const {
+ABIArgInfo
+MipsABIInfo::classifyArgumentType(QualType Ty, uint64_t &Offset) const {
if (isAggregateTypeForABI(Ty)) {
// Ignore empty aggregates.
- if (getContext().getTypeSize(Ty) == 0)
+ uint64_t TySize = getContext().getTypeSize(Ty);
+ if (TySize == 0)
return ABIArgInfo::getIgnore();
// Records with non trivial destructors/constructors should not be passed
// by value.
- if (isRecordWithNonTrivialDestructorOrCopyConstructor(Ty))
+ if (isRecordWithNonTrivialDestructorOrCopyConstructor(Ty)) {
+ Offset += 8;
return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
+ }
- llvm::Type *ResType;
- if ((ResType = HandleStructTy(Ty)))
- return ABIArgInfo::getDirect(ResType);
-
- return ABIArgInfo::getIndirect(0);
+ // If we have reached here, aggregates are passed either indirectly via a
+ // byval pointer or directly by coercing to another structure type. In the
+ // latter case, padding is inserted if the offset of the aggregate is
+ // unaligned.
+ llvm::Type *ResType = HandleStructTy(Ty);
+ uint64_t Align = getContext().getTypeAlign(Ty) / 8;
+ assert(Align <= 16 && "Alignment larger than 16 not handled.");
+ unsigned PaddingSize = (Offset % Align) * 8;
+ Offset = llvm::RoundUpToAlignment(Offset, std::max(Align, (uint64_t)8));
+ Offset += llvm::RoundUpToAlignment(TySize, 8);
+ return ResType ? ABIArgInfo::getDirect(ResType, 0, PaddingSize) :
+ ABIArgInfo::getIndirect(0);
}
// Treat an enum type as its underlying type.
if (const EnumType *EnumTy = Ty->getAs<EnumType>())
Ty = EnumTy->getDecl()->getIntegerType();
+ Offset += 8;
return (Ty->isPromotableIntegerType() ?
ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
}
@@ -3230,9 +3242,10 @@
void MipsABIInfo::computeInfo(CGFunctionInfo &FI) const {
FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
+ uint64_t Offset = 0;
for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
it != ie; ++it)
- it->info = classifyArgumentType(it->type);
+ it->info = classifyArgumentType(it->type, Offset);
}
llvm::Value* MipsABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
Index: lib/CodeGen/CGCall.cpp
===================================================================
--- lib/CodeGen/CGCall.cpp (revision 147536)
+++ lib/CodeGen/CGCall.cpp (working copy)
@@ -691,6 +691,9 @@
// generally likes scalar values better than FCAs.
llvm::Type *argType = argAI.getCoerceToType();
if (llvm::StructType *st = dyn_cast<llvm::StructType>(argType)) {
+ unsigned Size = argAI.getPaddingSize();
+ if (Size)
+ argTypes.push_back(llvm::IntegerType::get(getLLVMContext(), Size));
for (unsigned i = 0, e = st->getNumElements(); i != e; ++i)
argTypes.push_back(st->getElementType(i));
} else {
@@ -842,7 +845,8 @@
if (llvm::StructType *STy =
dyn_cast<llvm::StructType>(AI.getCoerceToType()))
- Index += STy->getNumElements()-1; // 1 will be added below.
+ // 1 will be added below.
+ Index += STy->getNumElements() + (AI.getPaddingSize() != 0) - 1;
break;
case ABIArgInfo::Indirect:
@@ -1030,7 +1034,8 @@
if (llvm::StructType *STy =
dyn_cast<llvm::StructType>(ArgI.getCoerceToType())) {
Ptr = Builder.CreateBitCast(Ptr, llvm::PointerType::getUnqual(STy));
-
+ if (ArgI.getPaddingSize())
+ ++AI;
for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) {
assert(AI != Fn->arg_end() && "Argument mismatch!");
AI->setName(Arg->getName() + ".coerce" + Twine(i));
@@ -1705,6 +1710,12 @@
dyn_cast<llvm::StructType>(ArgInfo.getCoerceToType())) {
SrcPtr = Builder.CreateBitCast(SrcPtr,
llvm::PointerType::getUnqual(STy));
+ unsigned Size = ArgInfo.getPaddingSize();
+ if (Size) {
+ llvm::Type *Ty = llvm::IntegerType::get(getLLVMContext(), Size);
+ Args.push_back(llvm::UndefValue::get(Ty));
+ ++IRArgNo;
+ }
for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) {
llvm::Value *EltPtr = Builder.CreateConstGEP2_32(SrcPtr, 0, i);
llvm::LoadInst *LI = Builder.CreateLoad(EltPtr);
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits