ABIInfo::~ABIInfo() {}
-static bool isRecordReturnIndirect(const RecordType *RT,
- CGCXXABI &CXXABI) {
- const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl());
- if (!RD)
- return false;
- return CXXABI.isReturnTypeIndirect(RD);
-}
-
-
-static bool isRecordReturnIndirect(QualType T, CGCXXABI &CXXABI) {
- const RecordType *RT = T->getAs<RecordType>();
- if (!RT)
- return false;
- return isRecordReturnIndirect(RT, CXXABI);
-}
-
static CGCXXABI::RecordArgABI getRecordArgABI(const RecordType *RT,
CGCXXABI &CXXABI) {
const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl());
ABIArgInfo classifyArgumentType(QualType RetTy) const;
void computeInfo(CGFunctionInfo &FI) const override {
- FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
+ if (!getCXXABI().classifyReturnType(FI))
+ FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
for (auto &I : FI.arguments())
I.info = classifyArgumentType(I.type);
}
}
ABIArgInfo DefaultABIInfo::classifyArgumentType(QualType Ty) const {
- if (isAggregateTypeForABI(Ty)) {
- // Records with non-trivial destructors/constructors should not be passed
- // by value.
- if (isRecordReturnIndirect(Ty, getCXXABI()))
- return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
-
+ if (isAggregateTypeForABI(Ty))
return ABIArgInfo::getIndirect(0);
- }
// Treat an enum type as its underlying type.
if (const EnumType *EnumTy = Ty->getAs<EnumType>())
};
void PNaClABIInfo::computeInfo(CGFunctionInfo &FI) const {
+ if (!getCXXABI().classifyReturnType(FI))
FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
- for (auto &I : FI.arguments())
- I.info = classifyArgumentType(I.type);
- }
+ for (auto &I : FI.arguments())
+ I.info = classifyArgumentType(I.type);
+}
llvm::Value *PNaClABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
CodeGenFunction &CGF) const {
return (Size == 8 || Size == 16 || Size == 32 || Size == 64);
}
- bool shouldReturnTypeInRegister(QualType Ty, ASTContext &Context,
- bool IsInstanceMethod) const;
+ bool shouldReturnTypeInRegister(QualType Ty, ASTContext &Context) const;
/// getIndirectResult - Give a source type \arg Ty, return a suitable result
/// such that the argument will be passed in memory.
unsigned getTypeStackAlignInBytes(QualType Ty, unsigned Align) const;
Class classify(QualType Ty) const;
- ABIArgInfo classifyReturnType(QualType RetTy, CCState &State,
- bool IsInstanceMethod) const;
+ ABIArgInfo classifyReturnType(QualType RetTy, CCState &State) const;
ABIArgInfo classifyArgumentType(QualType RetTy, CCState &State) const;
bool shouldUseInReg(QualType Ty, CCState &State, bool &NeedsPadding) const;
/// shouldReturnTypeInRegister - Determine if the given type should be
/// passed in a register (for the Darwin ABI).
-bool X86_32ABIInfo::shouldReturnTypeInRegister(QualType Ty, ASTContext &Context,
- bool IsInstanceMethod) const {
+bool X86_32ABIInfo::shouldReturnTypeInRegister(QualType Ty,
+ ASTContext &Context) const {
uint64_t Size = Context.getTypeSize(Ty);
// Type must be register sized.
// Arrays are treated like records.
if (const ConstantArrayType *AT = Context.getAsConstantArrayType(Ty))
- return shouldReturnTypeInRegister(AT->getElementType(), Context,
- IsInstanceMethod);
+ return shouldReturnTypeInRegister(AT->getElementType(), Context);
// Otherwise, it must be a record type.
const RecordType *RT = Ty->getAs<RecordType>();
// FIXME: Traverse bases here too.
- // For thiscall conventions, structures will never be returned in
- // a register. This is for compatibility with the MSVC ABI
- if (IsWin32StructABI && IsInstanceMethod && RT->isStructureType())
- return false;
-
// Structure types are passed in register if all fields would be
// passed in a register.
for (const auto *FD : RT->getDecl()->fields()) {
continue;
// Check fields recursively.
- if (!shouldReturnTypeInRegister(FD->getType(), Context, IsInstanceMethod))
+ if (!shouldReturnTypeInRegister(FD->getType(), Context))
return false;
}
return true;
return ABIArgInfo::getIndirect(/*Align=*/0, /*ByVal=*/false);
}
-ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy, CCState &State,
- bool IsInstanceMethod) const {
+ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy, CCState &State) const {
if (RetTy->isVoidType())
return ABIArgInfo::getIgnore();
if (isAggregateTypeForABI(RetTy)) {
if (const RecordType *RT = RetTy->getAs<RecordType>()) {
- if (isRecordReturnIndirect(RT, getCXXABI()))
- return getIndirectReturnResult(State);
-
// Structures with flexible arrays are always indirect.
if (RT->getDecl()->hasFlexibleArrayMember())
return getIndirectReturnResult(State);
// Small structures which are register sized are generally returned
// in a register.
- if (shouldReturnTypeInRegister(RetTy, getContext(), IsInstanceMethod)) {
+ if (shouldReturnTypeInRegister(RetTy, getContext())) {
uint64_t Size = getContext().getTypeSize(RetTy);
// As a special-case, if the struct is a "single-element" struct, and
else
State.FreeRegs = DefaultNumRegisterParameters;
- FI.getReturnInfo() =
- classifyReturnType(FI.getReturnType(), State, FI.isInstanceMethod());
-
- // On win32, swap the order of the first two parameters for instance methods
- // which are sret behind the scenes to match MSVC.
- if (IsWin32StructABI && FI.isInstanceMethod() &&
- FI.getReturnInfo().isIndirect()) {
- assert(FI.arg_size() >= 1 && "instance method should have this");
- FI.getReturnInfo().setSRetAfterThis(true);
- }
+ if (!getCXXABI().classifyReturnType(FI))
+ FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), State);
bool UsedInAlloca = false;
for (auto &I : FI.arguments()) {
void X86_64ABIInfo::computeInfo(CGFunctionInfo &FI) const {
- FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
+ if (!getCXXABI().classifyReturnType(FI))
+ FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
// Keep track of the number of assigned registers.
unsigned freeIntRegs = 6, freeSSERegs = 8;
const RecordType *RT = Ty->getAs<RecordType>();
if (RT) {
- if (IsReturnType) {
- if (isRecordReturnIndirect(RT, getCXXABI()))
- return ABIArgInfo::getIndirect(0, false);
- } else {
+ if (!IsReturnType) {
if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(RT, getCXXABI()))
return ABIArgInfo::getIndirect(0, RAA == CGCXXABI::RAA_DirectInMemory);
}
}
void WinX86_64ABIInfo::computeInfo(CGFunctionInfo &FI) const {
-
- QualType RetTy = FI.getReturnType();
- FI.getReturnInfo() = classify(RetTy, true);
-
- // On win64, swap the order of the first two parameters for instance methods
- // which are sret behind the scenes to match MSVC.
- if (FI.getReturnInfo().isIndirect() && FI.isInstanceMethod() &&
- getCXXABI().isSRetParameterAfterThis()) {
- assert(FI.arg_size() >= 1 && "instance method should have this");
- FI.getReturnInfo().setSRetAfterThis(true);
- }
+ if (!getCXXABI().classifyReturnType(FI))
+ FI.getReturnInfo() = classify(FI.getReturnType(), true);
for (auto &I : FI.arguments())
I.info = classify(I.type, false);
// entry. This would require changing the logic in PPCISelLowering
// when lowering the parameters in the caller and args in the callee.
void computeInfo(CGFunctionInfo &FI) const override {
- FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
+ if (!getCXXABI().classifyReturnType(FI))
+ FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
for (auto &I : FI.arguments()) {
// We rely on the default argument classification for the most part.
// One exception: An aggregate containing a single floating-point
FI.getRequiredArgs().getNumRequiredArgs() :
FI.arg_size());
- FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
+ if (!getCXXABI().classifyReturnType(FI))
+ FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
it != ie; ++it) {
unsigned PreAllocation = AllocatedVFP, PreGPR = AllocatedGPR;
// Structures with either a non-trivial destructor or a non-trivial
// copy constructor are always indirect.
- if (isRecordReturnIndirect(Ty, getCXXABI())) {
+ if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) {
AllocatedGPR++;
- return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
+ return ABIArgInfo::getIndirect(0, /*ByVal=*/RAA ==
+ CGCXXABI::RAA_DirectInMemory);
}
// Empty records are always ignored on Darwin, but actually passed in C++ mode
: ABIArgInfo::getDirect());
}
- // Structures with either a non-trivial destructor or a non-trivial
- // copy constructor are always indirect.
- if (isRecordReturnIndirect(RetTy, getCXXABI()))
- return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
-
if (isEmptyRecord(getContext(), RetTy, true))
return ABIArgInfo::getIgnore();
// unallocated are marked as unavailable.
resetAllocatedRegs();
- FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), FI.isVariadic());
+ if (getCXXABI().classifyReturnType(FI)) {
+ if (FI.getReturnInfo().isIndirect())
+ markAllocatedGPRs(1, 1);
+ } else {
+ FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), FI.isVariadic());
+ }
for (auto &I : FI.arguments()) {
unsigned PreAllocationVFPs = AllocatedVFPs;
unsigned PreAllocationGPRs = AllocatedGPRs;
ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
}
- // Structures with either a non-trivial destructor or a non-trivial
- // copy constructor are always indirect.
- if (isRecordReturnIndirect(RetTy, getCXXABI())) {
- markAllocatedGPRs(1, 1);
- return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
- }
-
// Are we following APCS?
if (getABIKind() == APCS) {
if (isEmptyRecord(getContext(), RetTy, false))
}
void NVPTXABIInfo::computeInfo(CGFunctionInfo &FI) const {
- FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
+ if (!getCXXABI().classifyReturnType(FI))
+ FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
for (auto &I : FI.arguments())
I.info = classifyArgumentType(I.type);
ABIArgInfo classifyArgumentType(QualType ArgTy) const;
void computeInfo(CGFunctionInfo &FI) const override {
- FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
+ if (!getCXXABI().classifyReturnType(FI))
+ FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
for (auto &I : FI.arguments())
I.info = classifyArgumentType(I.type);
}
return ABIArgInfo::getIgnore();
if (isAggregateTypeForABI(RetTy) || RetTy->isVectorType()) {
- if (isRecordReturnIndirect(RetTy, getCXXABI()))
- return ABIArgInfo::getIndirect(0);
-
if (Size <= 128) {
if (RetTy->isAnyComplexType())
return ABIArgInfo::getDirect();
void MipsABIInfo::computeInfo(CGFunctionInfo &FI) const {
ABIArgInfo &RetInfo = FI.getReturnInfo();
- RetInfo = classifyReturnType(FI.getReturnType());
+ if (!getCXXABI().classifyReturnType(FI))
+ RetInfo = classifyReturnType(FI.getReturnType());
// Check if a pointer to an aggregate is passed as a hidden argument.
uint64_t Offset = RetInfo.isIndirect() ? MinABIStackAlignInBytes : 0;
}
void HexagonABIInfo::computeInfo(CGFunctionInfo &FI) const {
- FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
+ if (!getCXXABI().classifyReturnType(FI))
+ FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
for (auto &I : FI.arguments())
I.info = classifyArgumentType(I.type);
}
ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
}
- // Structures with either a non-trivial destructor or a non-trivial
- // copy constructor are always indirect.
- if (isRecordReturnIndirect(RetTy, getCXXABI()))
- return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
-
if (isEmptyRecord(getContext(), RetTy, true))
return ABIArgInfo::getIgnore();
// WIN32: define void @"\01?big_arg@@YAXUBig@@@Z"(%struct.Big* byval align 4 %s)
// WIN64: define void @"\01?big_arg@@YAXUBig@@@Z"(%struct.Big* %s)
-// FIXME: Add WIN64 tests. Currently, even the method manglings are wrong (sic!).
class Class {
public:
Small thiscall_method_small() { return Small(); }
// LINUX: define {{.*}} void @_ZN5Class21thiscall_method_smallEv(%struct.Small* noalias sret %agg.result, %class.Class* %this)
// WIN32: define {{.*}} x86_thiscallcc void @"\01?thiscall_method_small@Class@@QAE?AUSmall@@XZ"(%class.Class* %this, %struct.Small* noalias sret %agg.result)
+ // WIN64: define linkonce_odr void @"\01?thiscall_method_small@Class@@QEAA?AUSmall@@XZ"(%class.Class* %this, %struct.Small* noalias sret %agg.result)
SmallWithCtor thiscall_method_small_with_ctor() { return SmallWithCtor(); }
// LINUX: define {{.*}} void @_ZN5Class31thiscall_method_small_with_ctorEv(%struct.SmallWithCtor* noalias sret %agg.result, %class.Class* %this)
// WIN32: define {{.*}} x86_thiscallcc void @"\01?thiscall_method_small_with_ctor@Class@@QAE?AUSmallWithCtor@@XZ"(%class.Class* %this, %struct.SmallWithCtor* noalias sret %agg.result)
+ // WIN64: define linkonce_odr void @"\01?thiscall_method_small_with_ctor@Class@@QEAA?AUSmallWithCtor@@XZ"(%class.Class* %this, %struct.SmallWithCtor* noalias sret %agg.result)
Small __cdecl cdecl_method_small() { return Small(); }
// LINUX: define {{.*}} void @_ZN5Class18cdecl_method_smallEv(%struct.Small* noalias sret %agg.result, %class.Class* %this)
// WIN32: define {{.*}} void @"\01?cdecl_method_small@Class@@QAA?AUSmall@@XZ"(%class.Class* %this, %struct.Small* noalias sret %agg.result)
+ // WIN64: define linkonce_odr void @"\01?cdecl_method_small@Class@@QEAA?AUSmall@@XZ"(%class.Class* %this, %struct.Small* noalias sret %agg.result)
Big __cdecl cdecl_method_big() { return Big(); }
// LINUX: define {{.*}} void @_ZN5Class16cdecl_method_bigEv(%struct.Big* noalias sret %agg.result, %class.Class* %this)
// WIN32: define {{.*}} void @"\01?cdecl_method_big@Class@@QAA?AUBig@@XZ"(%class.Class* %this, %struct.Big* noalias sret %agg.result)
+ // WIN64: define linkonce_odr void @"\01?cdecl_method_big@Class@@QEAA?AUBig@@XZ"(%class.Class* %this, %struct.Big* noalias sret %agg.result)
void thiscall_method_arg(Empty s) {}
// LINUX: define {{.*}} void @_ZN5Class19thiscall_method_argE5Empty(%class.Class* %this)
// WIN32: define {{.*}} void @"\01?thiscall_method_arg@Class@@QAEXUEmpty@@@Z"(%class.Class* %this, %struct.Empty* byval align 4 %s)
+ // WIN64: define linkonce_odr void @"\01?thiscall_method_arg@Class@@QEAAXUEmpty@@@Z"(%class.Class* %this, i8 %s.coerce)
void thiscall_method_arg(EmptyWithCtor s) {}
// LINUX: define {{.*}} void @_ZN5Class19thiscall_method_argE13EmptyWithCtor(%class.Class* %this)
// WIN32: define {{.*}} void @"\01?thiscall_method_arg@Class@@QAEXUEmptyWithCtor@@@Z"(%class.Class* %this, %struct.EmptyWithCtor* byval align 4 %s)
+ // WIN64: define linkonce_odr void @"\01?thiscall_method_arg@Class@@QEAAXUEmptyWithCtor@@@Z"(%class.Class* %this, i8 %s.coerce)
void thiscall_method_arg(Small s) {}
// LINUX: define {{.*}} void @_ZN5Class19thiscall_method_argE5Small(%class.Class* %this, %struct.Small* byval align 4 %s)
// WIN32: define {{.*}} void @"\01?thiscall_method_arg@Class@@QAEXUSmall@@@Z"(%class.Class* %this, %struct.Small* byval align 4 %s)
+ // WIN64: define linkonce_odr void @"\01?thiscall_method_arg@Class@@QEAAXUSmall@@@Z"(%class.Class* %this, i32 %s.coerce)
void thiscall_method_arg(SmallWithCtor s) {}
// LINUX: define {{.*}} void @_ZN5Class19thiscall_method_argE13SmallWithCtor(%class.Class* %this, %struct.SmallWithCtor* byval align 4 %s)
// WIN32: define {{.*}} void @"\01?thiscall_method_arg@Class@@QAEXUSmallWithCtor@@@Z"(%class.Class* %this, %struct.SmallWithCtor* byval align 4 %s)
+ // WIN64: define linkonce_odr void @"\01?thiscall_method_arg@Class@@QEAAXUSmallWithCtor@@@Z"(%class.Class* %this, i32 %s.coerce)
void thiscall_method_arg(Big s) {}
// LINUX: define {{.*}} void @_ZN5Class19thiscall_method_argE3Big(%class.Class* %this, %struct.Big* byval align 4 %s)
// WIN32: define {{.*}} void @"\01?thiscall_method_arg@Class@@QAEXUBig@@@Z"(%class.Class* %this, %struct.Big* byval align 4 %s)
+ // WIN64: define linkonce_odr void @"\01?thiscall_method_arg@Class@@QEAAXUBig@@@Z"(%class.Class* %this, %struct.Big* %s)
};
void use_class() {