Kill off the 'coerce' ABI passing form. Now 'direct' and 'extend' always

have a "coerce to" type which often matches the default lowering of Clang
type to LLVM IR type, but the coerce case can be handled by making them
not be the same.

This simplifies things and fixes issues where X86-64 abi lowering would 
return coerce after making preferred types exactly match up.  This caused
us to compile:

typedef float v4f32 __attribute__((__vector_size__(16)));
v4f32 foo(v4f32 X) {
  return X+X;
}

into this code at -O0:

define <4 x float> @foo(<4 x float> %X.coerce) nounwind {
entry:
  %retval = alloca <4 x float>, align 16          ; <<4 x float>*> [#uses=2]
  %coerce = alloca <4 x float>, align 16          ; <<4 x float>*> [#uses=2]
  %X.addr = alloca <4 x float>, align 16          ; <<4 x float>*> [#uses=3]
  store <4 x float> %X.coerce, <4 x float>* %coerce
  %X = load <4 x float>* %coerce                  ; <<4 x float>> [#uses=1]
  store <4 x float> %X, <4 x float>* %X.addr
  %tmp = load <4 x float>* %X.addr                ; <<4 x float>> [#uses=1]
  %tmp1 = load <4 x float>* %X.addr               ; <<4 x float>> [#uses=1]
  %add = fadd <4 x float> %tmp, %tmp1             ; <<4 x float>> [#uses=1]
  store <4 x float> %add, <4 x float>* %retval
  %0 = load <4 x float>* %retval                  ; <<4 x float>> [#uses=1]
  ret <4 x float> %0
}

Now we get:

define <4 x float> @foo(<4 x float> %X) nounwind {
entry:
  %X.addr = alloca <4 x float>, align 16          ; <<4 x float>*> [#uses=3]
  store <4 x float> %X, <4 x float>* %X.addr
  %tmp = load <4 x float>* %X.addr                ; <<4 x float>> [#uses=1]
  %tmp1 = load <4 x float>* %X.addr               ; <<4 x float>> [#uses=1]
  %add = fadd <4 x float> %tmp, %tmp1             ; <<4 x float>> [#uses=1]
  ret <4 x float> %add
}

This implements rdar://8248065

llvm-svn: 109733
This commit is contained in:
Chris Lattner 2010-07-29 06:26:06 +00:00
parent 9fa15c3608
commit fe34c1d53e
6 changed files with 189 additions and 199 deletions

View File

@ -38,17 +38,13 @@ namespace clang {
class ABIArgInfo {
public:
enum Kind {
Direct, /// Pass the argument directly using the normal
/// converted LLVM type. Complex and structure types
/// are passed using first class aggregates.
Direct, /// Pass the argument directly using the normal converted LLVM
/// type, or by coercing to another specified type
/// (stored in 'CoerceToType').
Extend, /// Valid only for integer argument types. Same as 'direct'
/// but also emit a zero/sign extension attribute.
Coerce, /// Only valid for aggregate return types, the argument
/// should be accessed by coercion to a provided type.
Indirect, /// Pass the argument indirectly via a hidden pointer
/// with the specified alignment (0 indicates default
/// alignment).
@ -79,8 +75,8 @@ namespace clang {
public:
ABIArgInfo() : TheKind(Direct), TypeData(0), UIntData(0) {}
static ABIArgInfo getDirect() {
return ABIArgInfo(Direct);
static ABIArgInfo getDirect(const llvm::Type *T = 0) {
return ABIArgInfo(Direct, T);
}
static ABIArgInfo getExtend() {
return ABIArgInfo(Extend);
@ -88,9 +84,6 @@ namespace clang {
static ABIArgInfo getIgnore() {
return ABIArgInfo(Ignore);
}
static ABIArgInfo getCoerce(const llvm::Type *T) {
return ABIArgInfo(Coerce, T);
}
static ABIArgInfo getIndirect(unsigned Alignment, bool ByVal = true) {
return ABIArgInfo(Indirect, 0, Alignment, ByVal);
}
@ -102,16 +95,23 @@ namespace clang {
bool isDirect() const { return TheKind == Direct; }
bool isExtend() const { return TheKind == Extend; }
bool isIgnore() const { return TheKind == Ignore; }
bool isCoerce() const { return TheKind == Coerce; }
bool isIndirect() const { return TheKind == Indirect; }
bool isExpand() const { return TheKind == Expand; }
// Coerce accessors
bool canHaveCoerceToType() const {
return TheKind == Direct || TheKind == Extend;
}
// Direct/Extend accessors
const llvm::Type *getCoerceToType() const {
assert(TheKind == Coerce && "Invalid kind!");
assert(canHaveCoerceToType() && "Invalid kind!");
return TypeData;
}
void setCoerceToType(const llvm::Type *T) {
assert(canHaveCoerceToType() && "Invalid kind!");
TypeData = T;
}
// Indirect accessors
unsigned getIndirectAlign() const {
assert(TheKind == Indirect && "Invalid kind!");

View File

@ -245,6 +245,18 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(CanQualType ResTy,
// Compute ABI information.
getABIInfo().computeInfo(*FI);
// Loop over all of the computed argument and return value info. If any of
// them are direct or extend without a specified coerce type, specify the
// default now.
ABIArgInfo &RetInfo = FI->getReturnInfo();
if (RetInfo.canHaveCoerceToType() && RetInfo.getCoerceToType() == 0)
RetInfo.setCoerceToType(ConvertTypeRecursive(FI->getReturnType()));
for (CGFunctionInfo::arg_iterator I = FI->arg_begin(), E = FI->arg_end();
I != E; ++I)
if (I->info.canHaveCoerceToType() && I->info.getCoerceToType() == 0)
I->info.setCoerceToType(ConvertTypeRecursive(I->type));
// If this is a top-level call and ConvertTypeRecursive hit unresolved pointer
// types, resolve them now. These pointers may point to this function, which
@ -592,7 +604,7 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool IsVariadic,
case ABIArgInfo::Extend:
case ABIArgInfo::Direct:
ResultType = ConvertType(RetTy, IsRecursive);
ResultType = RetAI.getCoerceToType();
break;
case ABIArgInfo::Indirect: {
@ -606,10 +618,6 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool IsVariadic,
case ABIArgInfo::Ignore:
ResultType = llvm::Type::getVoidTy(getLLVMContext());
break;
case ABIArgInfo::Coerce:
ResultType = RetAI.getCoerceToType();
break;
}
for (CGFunctionInfo::const_arg_iterator it = FI.arg_begin(),
@ -620,7 +628,15 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool IsVariadic,
case ABIArgInfo::Ignore:
break;
case ABIArgInfo::Coerce: {
case ABIArgInfo::Indirect: {
// indirect arguments are always on the stack, which is addr space #0.
const llvm::Type *LTy = ConvertTypeForMem(it->type, IsRecursive);
ArgTys.push_back(llvm::PointerType::getUnqual(LTy));
break;
}
case ABIArgInfo::Extend:
case ABIArgInfo::Direct:
// If the coerce-to type is a first class aggregate, flatten it. Either
// way is semantically identical, but fast-isel and the optimizer
// generally likes scalar values better than FCAs.
@ -632,19 +648,6 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool IsVariadic,
ArgTys.push_back(ArgTy);
}
break;
}
case ABIArgInfo::Indirect: {
// indirect arguments are always on the stack, which is addr space #0.
const llvm::Type *LTy = ConvertTypeForMem(it->type, IsRecursive);
ArgTys.push_back(llvm::PointerType::getUnqual(LTy));
break;
}
case ABIArgInfo::Extend:
case ABIArgInfo::Direct:
ArgTys.push_back(ConvertType(it->type, IsRecursive));
break;
case ABIArgInfo::Expand:
GetExpandedTypes(it->type, ArgTys, IsRecursive);
@ -713,8 +716,9 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
RetAttrs |= llvm::Attribute::SExt;
else if (RetTy->hasUnsignedIntegerRepresentation())
RetAttrs |= llvm::Attribute::ZExt;
// FALLTHROUGH
break;
case ABIArgInfo::Direct:
case ABIArgInfo::Ignore:
break;
case ABIArgInfo::Indirect:
@ -726,10 +730,6 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
llvm::Attribute::ReadNone);
break;
case ABIArgInfo::Ignore:
case ABIArgInfo::Coerce:
break;
case ABIArgInfo::Expand:
assert(0 && "Invalid ABI kind for return argument");
}
@ -752,15 +752,27 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
// 'restrict' -> 'noalias' is done in EmitFunctionProlog when we
// have the corresponding parameter variable. It doesn't make
// sense to do it here because parameters are so fucked up.
switch (AI.getKind()) {
case ABIArgInfo::Coerce:
case ABIArgInfo::Extend:
if (ParamType->isSignedIntegerType())
Attributes |= llvm::Attribute::SExt;
else if (ParamType->isUnsignedIntegerType())
Attributes |= llvm::Attribute::ZExt;
// FALL THROUGH
case ABIArgInfo::Direct:
if (RegParm > 0 &&
(ParamType->isIntegerType() || ParamType->isPointerType())) {
RegParm -=
(Context.getTypeSize(ParamType) + PointerWidth - 1) / PointerWidth;
if (RegParm >= 0)
Attributes |= llvm::Attribute::InReg;
}
// FIXME: handle sseregparm someday...
if (const llvm::StructType *STy =
dyn_cast<llvm::StructType>(AI.getCoerceToType()))
Index += STy->getNumElements();
else
++Index;
continue; // Skip index increment.
dyn_cast<llvm::StructType>(AI.getCoerceToType()))
Index += STy->getNumElements()-1; // 1 will be added below.
break;
case ABIArgInfo::Indirect:
if (AI.getIndirectByVal())
@ -773,23 +785,6 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
llvm::Attribute::ReadNone);
break;
case ABIArgInfo::Extend:
if (ParamType->isSignedIntegerType())
Attributes |= llvm::Attribute::SExt;
else if (ParamType->isUnsignedIntegerType())
Attributes |= llvm::Attribute::ZExt;
// FALLS THROUGH
case ABIArgInfo::Direct:
if (RegParm > 0 &&
(ParamType->isIntegerType() || ParamType->isPointerType())) {
RegParm -=
(Context.getTypeSize(ParamType) + PointerWidth - 1) / PointerWidth;
if (RegParm >= 0)
Attributes |= llvm::Attribute::InReg;
}
// FIXME: handle sseregparm someday...
break;
case ABIArgInfo::Ignore:
// Skip increment, no matching LLVM parameter.
continue;
@ -871,15 +866,12 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
case ABIArgInfo::Extend:
case ABIArgInfo::Direct: {
assert(AI != Fn->arg_end() && "Argument mismatch!");
llvm::Value *V = AI;
if (hasAggregateLLVMType(Ty)) {
// Create a temporary alloca to hold the argument; the rest of
// codegen expects to access aggregates & complex values by
// reference.
V = CreateMemTemp(Ty);
Builder.CreateStore(AI, V);
} else {
// If we have the trivial case, handle it with no muss and fuss.
if (!isa<llvm::StructType>(ArgI.getCoerceToType()) &&
ArgI.getCoerceToType() == ConvertType(Ty)) {
assert(AI != Fn->arg_end() && "Argument mismatch!");
llvm::Value *V = AI;
if (Arg->getType().isRestrictQualified())
AI->addAttr(llvm::Attribute::NoAlias);
@ -888,40 +880,10 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
// "void a(x) short x; {..."
V = EmitScalarConversion(V, Ty, Arg->getType());
}
}
EmitParmDecl(*Arg, V);
break;
}
case ABIArgInfo::Expand: {
// If this structure was expanded into multiple arguments then
// we need to create a temporary and reconstruct it from the
// arguments.
llvm::Value *Temp = CreateMemTemp(Ty, Arg->getName() + ".addr");
// FIXME: What are the right qualifiers here?
llvm::Function::arg_iterator End =
ExpandTypeFromArgs(Ty, LValue::MakeAddr(Temp, Qualifiers()), AI);
EmitParmDecl(*Arg, Temp);
// Name the arguments used in expansion and increment AI.
unsigned Index = 0;
for (; AI != End; ++AI, ++Index)
AI->setName(Arg->getName() + "." + llvm::Twine(Index));
continue;
}
case ABIArgInfo::Ignore:
// Initialize the local variable appropriately.
if (hasAggregateLLVMType(Ty)) {
EmitParmDecl(*Arg, CreateMemTemp(Ty));
} else {
EmitParmDecl(*Arg, llvm::UndefValue::get(ConvertType(Arg->getType())));
EmitParmDecl(*Arg, V);
break;
}
// Skip increment, no matching LLVM parameter.
continue;
case ABIArgInfo::Coerce: {
llvm::AllocaInst *Alloca = CreateMemTemp(Ty, "coerce");
// The alignment we need to use is the max of the requested alignment for
@ -968,6 +930,33 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
EmitParmDecl(*Arg, V);
continue; // Skip ++AI increment, already done.
}
case ABIArgInfo::Expand: {
// If this structure was expanded into multiple arguments then
// we need to create a temporary and reconstruct it from the
// arguments.
llvm::Value *Temp = CreateMemTemp(Ty, Arg->getName() + ".addr");
// FIXME: What are the right qualifiers here?
llvm::Function::arg_iterator End =
ExpandTypeFromArgs(Ty, LValue::MakeAddr(Temp, Qualifiers()), AI);
EmitParmDecl(*Arg, Temp);
// Name the arguments used in expansion and increment AI.
unsigned Index = 0;
for (; AI != End; ++AI, ++Index)
AI->setName(Arg->getName() + "." + llvm::Twine(Index));
continue;
}
case ABIArgInfo::Ignore:
// Initialize the local variable appropriately.
if (hasAggregateLLVMType(Ty))
EmitParmDecl(*Arg, CreateMemTemp(Ty));
else
EmitParmDecl(*Arg, llvm::UndefValue::get(ConvertType(Arg->getType())));
// Skip increment, no matching LLVM parameter.
continue;
}
++AI;
@ -1001,38 +990,39 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI) {
break;
case ABIArgInfo::Extend:
case ABIArgInfo::Direct: {
// The internal return value temp always will have pointer-to-return-type
// type, just do a load.
// If the instruction right before the insertion point is a store to the
// return value, we can elide the load, zap the store, and usually zap the
// alloca.
llvm::BasicBlock *InsertBB = Builder.GetInsertBlock();
llvm::StoreInst *SI = 0;
if (InsertBB->empty() ||
!(SI = dyn_cast<llvm::StoreInst>(&InsertBB->back())) ||
SI->getPointerOperand() != ReturnValue || SI->isVolatile()) {
RV = Builder.CreateLoad(ReturnValue);
} else {
// Get the stored value and nuke the now-dead store.
RetDbgLoc = SI->getDebugLoc();
RV = SI->getValueOperand();
SI->eraseFromParent();
// If that was the only use of the return value, nuke it as well now.
if (ReturnValue->use_empty() && isa<llvm::AllocaInst>(ReturnValue)) {
cast<llvm::AllocaInst>(ReturnValue)->eraseFromParent();
ReturnValue = 0;
case ABIArgInfo::Direct:
if (RetAI.getCoerceToType() == ConvertType(RetTy)) {
// The internal return value temp always will have pointer-to-return-type
// type, just do a load.
// If the instruction right before the insertion point is a store to the
// return value, we can elide the load, zap the store, and usually zap the
// alloca.
llvm::BasicBlock *InsertBB = Builder.GetInsertBlock();
llvm::StoreInst *SI = 0;
if (InsertBB->empty() ||
!(SI = dyn_cast<llvm::StoreInst>(&InsertBB->back())) ||
SI->getPointerOperand() != ReturnValue || SI->isVolatile()) {
RV = Builder.CreateLoad(ReturnValue);
} else {
// Get the stored value and nuke the now-dead store.
RetDbgLoc = SI->getDebugLoc();
RV = SI->getValueOperand();
SI->eraseFromParent();
// If that was the only use of the return value, nuke it as well now.
if (ReturnValue->use_empty() && isa<llvm::AllocaInst>(ReturnValue)) {
cast<llvm::AllocaInst>(ReturnValue)->eraseFromParent();
ReturnValue = 0;
}
}
} else {
RV = CreateCoercedLoad(ReturnValue, RetAI.getCoerceToType(), *this);
}
break;
}
case ABIArgInfo::Ignore:
break;
case ABIArgInfo::Coerce:
RV = CreateCoercedLoad(ReturnValue, RetAI.getCoerceToType(), *this);
case ABIArgInfo::Ignore:
break;
case ABIArgInfo::Expand:
@ -1145,24 +1135,20 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
}
break;
case ABIArgInfo::Extend:
case ABIArgInfo::Direct:
if (RV.isScalar()) {
Args.push_back(RV.getScalarVal());
} else if (RV.isComplex()) {
llvm::Value *Tmp = llvm::UndefValue::get(ConvertType(I->second));
Tmp = Builder.CreateInsertValue(Tmp, RV.getComplexVal().first, 0);
Tmp = Builder.CreateInsertValue(Tmp, RV.getComplexVal().second, 1);
Args.push_back(Tmp);
} else {
Args.push_back(Builder.CreateLoad(RV.getAggregateAddr()));
}
break;
case ABIArgInfo::Ignore:
break;
case ABIArgInfo::Extend:
case ABIArgInfo::Direct: {
if (!isa<llvm::StructType>(ArgInfo.getCoerceToType()) &&
ArgInfo.getCoerceToType() == ConvertType(info_it->type)) {
if (RV.isScalar())
Args.push_back(RV.getScalarVal());
else
Args.push_back(Builder.CreateLoad(RV.getAggregateAddr()));
break;
}
case ABIArgInfo::Coerce: {
// FIXME: Avoid the conversion through memory if possible.
llvm::Value *SrcPtr;
if (RV.isScalar()) {
@ -1286,32 +1272,33 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
return RValue::getAggregate(Args[0]);
return RValue::get(EmitLoadOfScalar(Args[0], false, RetTy));
case ABIArgInfo::Extend:
case ABIArgInfo::Direct:
if (RetTy->isAnyComplexType()) {
llvm::Value *Real = Builder.CreateExtractValue(CI, 0);
llvm::Value *Imag = Builder.CreateExtractValue(CI, 1);
return RValue::getComplex(std::make_pair(Real, Imag));
}
if (CodeGenFunction::hasAggregateLLVMType(RetTy)) {
llvm::Value *DestPtr = ReturnValue.getValue();
bool DestIsVolatile = ReturnValue.isVolatile();
if (!DestPtr) {
DestPtr = CreateMemTemp(RetTy, "agg.tmp");
DestIsVolatile = false;
}
Builder.CreateStore(CI, DestPtr, DestIsVolatile);
return RValue::getAggregate(DestPtr);
}
return RValue::get(CI);
case ABIArgInfo::Ignore:
// If we are ignoring an argument that had a result, make sure to
// construct the appropriate return value for our caller.
return GetUndefRValue(RetTy);
case ABIArgInfo::Extend:
case ABIArgInfo::Direct: {
if (RetAI.getCoerceToType() == ConvertType(RetTy)) {
if (RetTy->isAnyComplexType()) {
llvm::Value *Real = Builder.CreateExtractValue(CI, 0);
llvm::Value *Imag = Builder.CreateExtractValue(CI, 1);
return RValue::getComplex(std::make_pair(Real, Imag));
}
if (CodeGenFunction::hasAggregateLLVMType(RetTy)) {
llvm::Value *DestPtr = ReturnValue.getValue();
bool DestIsVolatile = ReturnValue.isVolatile();
case ABIArgInfo::Coerce: {
if (!DestPtr) {
DestPtr = CreateMemTemp(RetTy, "agg.tmp");
DestIsVolatile = false;
}
Builder.CreateStore(CI, DestPtr, DestIsVolatile);
return RValue::getAggregate(DestPtr);
}
return RValue::get(CI);
}
llvm::Value *DestPtr = ReturnValue.getValue();
bool DestIsVolatile = ReturnValue.isVolatile();

View File

@ -14,13 +14,12 @@
#ifndef CLANG_CODEGEN_CODEGENTYPES_H
#define CLANG_CODEGEN_CODEGENTYPES_H
#include "CGCall.h"
#include "GlobalDecl.h"
#include "llvm/Module.h"
#include "llvm/ADT/DenseMap.h"
#include <vector>
#include "CGCall.h"
#include "GlobalDecl.h"
namespace llvm {
class FunctionType;
class Module;

View File

@ -56,7 +56,11 @@ void ABIArgInfo::dump() const {
OS << "(ABIArgInfo Kind=";
switch (TheKind) {
case Direct:
OS << "Direct";
OS << "Direct Type=";
if (const llvm::Type *Ty = getCoerceToType())
Ty->print(OS);
else
OS << "null";
break;
case Extend:
OS << "Extend";
@ -64,10 +68,6 @@ void ABIArgInfo::dump() const {
case Ignore:
OS << "Ignore";
break;
case Coerce:
OS << "Coerce Type=";
getCoerceToType()->print(OS);
break;
case Indirect:
OS << "Indirect Align=" << getIndirectAlign()
<< " Byal=" << getIndirectByVal();
@ -451,14 +451,14 @@ ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy) const {
// registers and we need to make sure to pick a type the LLVM
// backend will like.
if (Size == 128)
return ABIArgInfo::getCoerce(llvm::VectorType::get(
return ABIArgInfo::getDirect(llvm::VectorType::get(
llvm::Type::getInt64Ty(getVMContext()), 2));
// Always return in register if it fits in a general purpose
// register, or if it is 64 bits and has a single element.
if ((Size == 8 || Size == 16 || Size == 32) ||
(Size == 64 && VT->getNumElements() == 1))
return ABIArgInfo::getCoerce(llvm::IntegerType::get(getVMContext(),
return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(),
Size));
return ABIArgInfo::getIndirect(0);
@ -491,7 +491,7 @@ ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy) const {
// bit-fields can adjust that to be larger than the single
// element type.
uint64_t Size = getContext().getTypeSize(RetTy);
return ABIArgInfo::getCoerce(
return ABIArgInfo::getDirect(
llvm::IntegerType::get(getVMContext(), (unsigned)Size));
}
@ -499,20 +499,20 @@ ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy) const {
assert(getContext().getTypeSize(RetTy) ==
getContext().getTypeSize(SeltTy) &&
"Unexpect single element structure size!");
return ABIArgInfo::getCoerce(llvm::Type::getFloatTy(getVMContext()));
return ABIArgInfo::getDirect(llvm::Type::getFloatTy(getVMContext()));
}
if (BT->getKind() == BuiltinType::Double) {
assert(getContext().getTypeSize(RetTy) ==
getContext().getTypeSize(SeltTy) &&
"Unexpect single element structure size!");
return ABIArgInfo::getCoerce(llvm::Type::getDoubleTy(getVMContext()));
return ABIArgInfo::getDirect(llvm::Type::getDoubleTy(getVMContext()));
}
} else if (SeltTy->isPointerType()) {
// FIXME: It would be really nice if this could come out as the proper
// pointer type.
const llvm::Type *PtrTy = llvm::Type::getInt8PtrTy(getVMContext());
return ABIArgInfo::getCoerce(PtrTy);
return ABIArgInfo::getDirect(PtrTy);
} else if (SeltTy->isVectorType()) {
// 64- and 128-bit vectors are never returned in a
// register when inside a structure.
@ -528,7 +528,7 @@ ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy) const {
// in a register.
if (X86_32ABIInfo::shouldReturnTypeInRegister(RetTy, getContext())) {
uint64_t Size = getContext().getTypeSize(RetTy);
return ABIArgInfo::getCoerce(llvm::IntegerType::get(getVMContext(),Size));
return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(),Size));
}
return ABIArgInfo::getIndirect(0);
@ -1139,7 +1139,7 @@ ABIArgInfo X86_64ABIInfo::getCoerceResult(QualType Ty,
CoerceTo = llvm::Type::getFloatTy(CoerceTo->getContext());
}
return ABIArgInfo::getCoerce(CoerceTo);
return ABIArgInfo::getDirect(CoerceTo);
}
ABIArgInfo X86_64ABIInfo::getIndirectReturnResult(QualType Ty) const {
@ -1195,8 +1195,6 @@ const llvm::Type *X86_64ABIInfo::Get16ByteVectorType(QualType Ty) const {
STy = dyn_cast<llvm::StructType>(IRType);
}
// If the preferred type is a 16-byte vector, prefer to pass it.
if (const llvm::VectorType *VT = dyn_cast<llvm::VectorType>(IRType)){
const llvm::Type *EltTy = VT->getElementType();
@ -1622,7 +1620,7 @@ llvm::Value *X86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
"reg_save_area");
if (neededInt && neededSSE) {
// FIXME: Cleanup.
assert(AI.isCoerce() && "Unexpected ABI info for mixed regs");
assert(AI.isDirect() && "Unexpected ABI info for mixed regs");
const llvm::StructType *ST = cast<llvm::StructType>(AI.getCoerceToType());
llvm::Value *Tmp = CGF.CreateTempAlloca(ST);
assert(ST->getNumElements() == 2 && "Unexpected ABI info for mixed regs");
@ -1948,7 +1946,7 @@ ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty) const {
LLVMFields.push_back(llvm::ArrayType::get(ElemTy, SizeRegs));
const llvm::Type* STy = llvm::StructType::get(getVMContext(), LLVMFields,
true);
return ABIArgInfo::getCoerce(STy);
return ABIArgInfo::getDirect(STy);
}
static bool isIntegerLikeType(QualType Ty, ASTContext &Context,
@ -2064,7 +2062,7 @@ ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy) const {
// FIXME: Consider using 2 x vector types if the back end handles them
// correctly.
if (RetTy->isAnyComplexType())
return ABIArgInfo::getCoerce(llvm::IntegerType::get(getVMContext(),
return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(),
getContext().getTypeSize(RetTy)));
// Integer like structures are returned in r0.
@ -2072,10 +2070,10 @@ ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy) const {
// Return in the smallest viable integer type.
uint64_t Size = getContext().getTypeSize(RetTy);
if (Size <= 8)
return ABIArgInfo::getCoerce(llvm::Type::getInt8Ty(getVMContext()));
return ABIArgInfo::getDirect(llvm::Type::getInt8Ty(getVMContext()));
if (Size <= 16)
return ABIArgInfo::getCoerce(llvm::Type::getInt16Ty(getVMContext()));
return ABIArgInfo::getCoerce(llvm::Type::getInt32Ty(getVMContext()));
return ABIArgInfo::getDirect(llvm::Type::getInt16Ty(getVMContext()));
return ABIArgInfo::getDirect(llvm::Type::getInt32Ty(getVMContext()));
}
// Otherwise return in memory.
@ -2093,10 +2091,10 @@ ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy) const {
if (Size <= 32) {
// Return in the smallest viable integer type.
if (Size <= 8)
return ABIArgInfo::getCoerce(llvm::Type::getInt8Ty(getVMContext()));
return ABIArgInfo::getDirect(llvm::Type::getInt8Ty(getVMContext()));
if (Size <= 16)
return ABIArgInfo::getCoerce(llvm::Type::getInt16Ty(getVMContext()));
return ABIArgInfo::getCoerce(llvm::Type::getInt32Ty(getVMContext()));
return ABIArgInfo::getDirect(llvm::Type::getInt16Ty(getVMContext()));
return ABIArgInfo::getDirect(llvm::Type::getInt32Ty(getVMContext()));
}
return ABIArgInfo::getIndirect(0);

View File

@ -152,10 +152,16 @@ struct f23S f24(struct f23S *X, struct f24s *P2) {
// CHECK: define %struct.f24s @f24(%struct.f23S* %X, %struct.f24s* %P2)
}
// rdar://8248065
typedef float v4f32 __attribute__((__vector_size__(16)));
v4f32 f25(v4f32 X) {
// CHECK: define <4 x float> @f25(<4 x float> %X.coerce)
// CHECK: define <4 x float> @f25(<4 x float> %X)
// CHECK-NOT: alloca
// CHECK: %X.addr = alloca <4 x float>
// CHECK-NOT: alloca
// CHECK: store <4 x float> %X, <4 x float>* %X.addr
// CHECK-NOT: store
// CHECK: ret <4 x float>
return X+X;
}

View File

@ -23,7 +23,7 @@ struct s3_0 {};
struct s3_1 { struct s3_0 a; long b; };
void f3(struct s3_1 x) {}
// CHECK: define i64 @_Z4f4_0M2s4i(i64 %a.coerce)
// CHECK: define i64 @_Z4f4_0M2s4i(i64 %a)
// CHECK: define {{.*}} @_Z4f4_1M2s4FivE(i64 %a.coerce0, i64 %a.coerce1)
struct s4 {};
typedef int s4::* s4_mdp;