forked from OSchip/llvm-project
Build correct coercion types in SparcV9ABIInfo.
The coercion type serves two purposes: 1. Pad structs to a multiple of 64 bits, so they are passed 'left-aligned' in registers. 2. Expose aligned floating point elements as first-level elements, so the code generator knows to pass them in floating point registers. We also compute the InReg flag which indicates that the struct contains aligned 32-bit floats. This flag is used by the code generator to pick the right registers. llvm-svn: 182753
This commit is contained in:
parent
f92c4a814a
commit
02dc6a1451
|
@ -5161,6 +5161,117 @@ private:
|
||||||
virtual void computeInfo(CGFunctionInfo &FI) const;
|
virtual void computeInfo(CGFunctionInfo &FI) const;
|
||||||
virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
|
virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
|
||||||
CodeGenFunction &CGF) const;
|
CodeGenFunction &CGF) const;
|
||||||
|
|
||||||
|
// Coercion type builder for structs passed in registers. The coercion type
|
||||||
|
// serves two purposes:
|
||||||
|
//
|
||||||
|
// 1. Pad structs to a multiple of 64 bits, so they are passed 'left-aligned'
|
||||||
|
// in registers.
|
||||||
|
// 2. Expose aligned floating point elements as first-level elements, so the
|
||||||
|
// code generator knows to pass them in floating point registers.
|
||||||
|
//
|
||||||
|
// We also compute the InReg flag which indicates that the struct contains
|
||||||
|
// aligned 32-bit floats.
|
||||||
|
//
|
||||||
|
struct CoerceBuilder {
|
||||||
|
llvm::LLVMContext &Context;
|
||||||
|
const llvm::DataLayout &DL;
|
||||||
|
SmallVector<llvm::Type*, 8> Elems;
|
||||||
|
uint64_t Size;
|
||||||
|
bool InReg;
|
||||||
|
|
||||||
|
CoerceBuilder(llvm::LLVMContext &c, const llvm::DataLayout &dl)
|
||||||
|
: Context(c), DL(dl), Size(0), InReg(false) {}
|
||||||
|
|
||||||
|
// Pad Elems with integers until Size is ToSize.
|
||||||
|
void pad(uint64_t ToSize) {
|
||||||
|
assert(ToSize >= Size && "Cannot remove elements");
|
||||||
|
if (ToSize == Size)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Finish the current 64-bit word.
|
||||||
|
uint64_t Aligned = llvm::RoundUpToAlignment(Size, 64);
|
||||||
|
if (Aligned > Size && Aligned <= ToSize) {
|
||||||
|
Elems.push_back(llvm::IntegerType::get(Context, Aligned - Size));
|
||||||
|
Size = Aligned;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add whole 64-bit words.
|
||||||
|
while (Size + 64 <= ToSize) {
|
||||||
|
Elems.push_back(llvm::Type::getInt64Ty(Context));
|
||||||
|
Size += 64;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Final in-word padding.
|
||||||
|
if (Size < ToSize) {
|
||||||
|
Elems.push_back(llvm::IntegerType::get(Context, ToSize - Size));
|
||||||
|
Size = ToSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a floating point element at Offset.
|
||||||
|
void addFloat(uint64_t Offset, llvm::Type *Ty, unsigned Bits) {
|
||||||
|
// Unaligned floats are treated as integers.
|
||||||
|
if (Offset % Bits)
|
||||||
|
return;
|
||||||
|
// The InReg flag is only required if there are any floats < 64 bits.
|
||||||
|
if (Bits < 64)
|
||||||
|
InReg = true;
|
||||||
|
pad(Offset);
|
||||||
|
Elems.push_back(Ty);
|
||||||
|
Size = Offset + Bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a struct type to the coercion type, starting at Offset (in bits).
|
||||||
|
void addStruct(uint64_t Offset, llvm::StructType *StrTy) {
|
||||||
|
const llvm::StructLayout *Layout = DL.getStructLayout(StrTy);
|
||||||
|
for (unsigned i = 0, e = StrTy->getNumElements(); i != e; ++i) {
|
||||||
|
llvm::Type *ElemTy = StrTy->getElementType(i);
|
||||||
|
uint64_t ElemOffset = Offset + Layout->getElementOffsetInBits(i);
|
||||||
|
switch (ElemTy->getTypeID()) {
|
||||||
|
case llvm::Type::StructTyID:
|
||||||
|
addStruct(ElemOffset, cast<llvm::StructType>(ElemTy));
|
||||||
|
break;
|
||||||
|
case llvm::Type::FloatTyID:
|
||||||
|
addFloat(ElemOffset, ElemTy, 32);
|
||||||
|
break;
|
||||||
|
case llvm::Type::DoubleTyID:
|
||||||
|
addFloat(ElemOffset, ElemTy, 64);
|
||||||
|
break;
|
||||||
|
case llvm::Type::FP128TyID:
|
||||||
|
addFloat(ElemOffset, ElemTy, 128);
|
||||||
|
break;
|
||||||
|
case llvm::Type::PointerTyID:
|
||||||
|
if (ElemOffset % 64 == 0) {
|
||||||
|
pad(ElemOffset);
|
||||||
|
Elems.push_back(ElemTy);
|
||||||
|
Size += 64;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if Ty is a usable substitute for the coercion type.
|
||||||
|
bool isUsableType(llvm::StructType *Ty) const {
|
||||||
|
if (Ty->getNumElements() != Elems.size())
|
||||||
|
return false;
|
||||||
|
for (unsigned i = 0, e = Elems.size(); i != e; ++i)
|
||||||
|
if (Elems[i] != Ty->getElementType(i))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the coercion type as a literal struct type.
|
||||||
|
llvm::Type *getType() const {
|
||||||
|
if (Elems.size() == 1)
|
||||||
|
return Elems.front();
|
||||||
|
else
|
||||||
|
return llvm::StructType::get(Context, Elems);
|
||||||
|
}
|
||||||
|
};
|
||||||
};
|
};
|
||||||
} // end anonymous namespace
|
} // end anonymous namespace
|
||||||
|
|
||||||
|
@ -5189,9 +5300,22 @@ SparcV9ABIInfo::classifyType(QualType Ty, unsigned SizeLimit) const {
|
||||||
return ABIArgInfo::getDirect();
|
return ABIArgInfo::getDirect();
|
||||||
|
|
||||||
// This is a small aggregate type that should be passed in registers.
|
// This is a small aggregate type that should be passed in registers.
|
||||||
// FIXME: Compute the correct coersion type.
|
// Build a coercion type from the LLVM struct type.
|
||||||
// FIXME: Ensure any float members are passed in float registers.
|
llvm::StructType *StrTy = dyn_cast<llvm::StructType>(CGT.ConvertType(Ty));
|
||||||
return ABIArgInfo::getDirect();
|
if (!StrTy)
|
||||||
|
return ABIArgInfo::getDirect();
|
||||||
|
|
||||||
|
CoerceBuilder CB(getVMContext(), getDataLayout());
|
||||||
|
CB.addStruct(0, StrTy);
|
||||||
|
CB.pad(llvm::RoundUpToAlignment(CB.DL.getTypeSizeInBits(StrTy), 64));
|
||||||
|
|
||||||
|
// Try to use the original type for coercion.
|
||||||
|
llvm::Type *CoerceTy = CB.isUsableType(StrTy) ? StrTy : CB.getType();
|
||||||
|
|
||||||
|
if (CB.InReg)
|
||||||
|
return ABIArgInfo::getDirectInReg(CoerceTy);
|
||||||
|
else
|
||||||
|
return ABIArgInfo::getDirect(CoerceTy);
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::Value *SparcV9ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
|
llvm::Value *SparcV9ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
|
||||||
|
|
|
@ -56,3 +56,37 @@ struct large f_large(struct large x) {
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A 64-bit struct fits in a register.
|
||||||
|
struct reg {
|
||||||
|
int a, b;
|
||||||
|
};
|
||||||
|
|
||||||
|
// CHECK: define i64 @f_reg(i64 %x.coerce)
|
||||||
|
struct reg f_reg(struct reg x) {
|
||||||
|
x.a += x.b;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Structs with mixed int and float parts require the inreg attribute.
|
||||||
|
struct mixed {
|
||||||
|
int a;
|
||||||
|
float b;
|
||||||
|
};
|
||||||
|
|
||||||
|
// CHECK: @f_mixed(i32 inreg %x.coerce0, float inreg %x.coerce1)
|
||||||
|
// FIXME: The return value should also be 'inreg'.
|
||||||
|
struct mixed f_mixed(struct mixed x) {
|
||||||
|
x.a += 1;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Struct with padding.
|
||||||
|
struct mixed2 {
|
||||||
|
int a;
|
||||||
|
double b;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mixed2 f_mixed2(struct mixed2 x) {
|
||||||
|
x.a += 1;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue