r200597 - [ms-cxxabi] Use inalloca on win32 when passing non-trivial C++ objects
Reid Kleckner
reid at kleckner.net
Fri Jan 31 16:04:46 PST 2014
Author: rnk
Date: Fri Jan 31 18:04:45 2014
New Revision: 200597
URL: http://llvm.org/viewvc/llvm-project?rev=200597&view=rev
Log:
[ms-cxxabi] Use inalloca on win32 when passing non-trivial C++ objects
When a non-trivial parameter is present, clang now gathers up all the
parameters that lack inreg and puts them into a packed struct. MSVC
always aligns each parameter to 4 bytes and no more, so this is a pretty
simple struct to lay out.
On win64, non-trivial records are passed indirectly. Prior to this
change, clang was incorrectly using byval on win64.
I'm able to self-host a working clang with this change and additional
LLVM patches.
Reviewers: rsmith
Differential Revision: http://llvm-reviews.chandlerc.com/D2636
Added:
cfe/trunk/test/CodeGenCXX/microsoft-abi-byval-sret.cpp
cfe/trunk/test/CodeGenCXX/microsoft-abi-byval-vararg.cpp
Modified:
cfe/trunk/include/clang/CodeGen/CGFunctionInfo.h
cfe/trunk/lib/CodeGen/CGCall.cpp
cfe/trunk/lib/CodeGen/CGCall.h
cfe/trunk/lib/CodeGen/CGClass.cpp
cfe/trunk/lib/CodeGen/CGDecl.cpp
cfe/trunk/lib/CodeGen/CodeGenFunction.cpp
cfe/trunk/lib/CodeGen/CodeGenFunction.h
cfe/trunk/lib/CodeGen/CodeGenTypes.h
cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp
cfe/trunk/lib/CodeGen/TargetInfo.cpp
cfe/trunk/test/CodeGenCXX/copy-constructor-elim.cpp
cfe/trunk/test/CodeGenCXX/microsoft-abi-arg-order.cpp
cfe/trunk/test/CodeGenCXX/microsoft-abi-exceptions.cpp
cfe/trunk/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp
cfe/trunk/test/CodeGenObjCXX/microsoft-abi-arc-param-order.mm
Modified: cfe/trunk/include/clang/CodeGen/CGFunctionInfo.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/CodeGen/CGFunctionInfo.h?rev=200597&r1=200596&r2=200597&view=diff
==============================================================================
--- cfe/trunk/include/clang/CodeGen/CGFunctionInfo.h (original)
+++ cfe/trunk/include/clang/CodeGen/CGFunctionInfo.h Fri Jan 31 18:04:45 2014
@@ -23,9 +23,12 @@
namespace llvm {
class Type;
+ class StructType;
}
namespace clang {
+class Decl;
+
namespace CodeGen {
/// ABIArgInfo - Helper class to encapsulate information about how a
@@ -59,7 +62,15 @@ public:
/// are all scalar types or are themselves expandable types.
Expand,
- KindFirst=Direct, KindLast=Expand
+ /// InAlloca - Pass the argument directly using the LLVM inalloca attribute.
+ /// This is similar to 'direct', except it only applies to arguments stored
+ /// in memory and forbids any implicit copies. When applied to a return
+ /// type, it means the value is returned indirectly via an implicit sret
+ /// parameter stored in the argument struct.
+ InAlloca,
+
+ KindFirst = Direct,
+ KindLast = InAlloca
};
private:
@@ -102,6 +113,9 @@ public:
return ABIArgInfo(Indirect, 0, Alignment, ByVal, Realign, false, false,
Padding);
}
+ static ABIArgInfo getInAlloca(unsigned FieldIndex) {
+ return ABIArgInfo(InAlloca, 0, FieldIndex, false, false, false, false, 0);
+ }
static ABIArgInfo getIndirectInReg(unsigned Alignment, bool ByVal = true
, bool Realign = false) {
return ABIArgInfo(Indirect, 0, Alignment, ByVal, Realign, true, false, 0);
@@ -117,6 +131,7 @@ public:
Kind getKind() const { return TheKind; }
bool isDirect() const { return TheKind == Direct; }
+ bool isInAlloca() const { return TheKind == InAlloca; }
bool isExtend() const { return TheKind == Extend; }
bool isIgnore() const { return TheKind == Ignore; }
bool isIndirect() const { return TheKind == Indirect; }
@@ -171,6 +186,11 @@ public:
return BoolData1;
}
+ unsigned getInAllocaFieldIndex() const {
+ assert(TheKind == InAlloca && "Invalid kind!");
+ return UIntData;
+ }
+
void dump() const;
};
@@ -257,6 +277,10 @@ class CGFunctionInfo : public llvm::Fold
RequiredArgs Required;
+ /// The struct representing all arguments passed in memory. Only used when
+ /// passing non-trivial types with inalloca. Not part of the profile.
+ llvm::StructType *ArgStruct;
+
unsigned NumArgs;
ArgInfo *getArgsBuffer() {
return reinterpret_cast<ArgInfo*>(this+1);
@@ -330,6 +354,13 @@ public:
ABIArgInfo &getReturnInfo() { return getArgsBuffer()[0].info; }
const ABIArgInfo &getReturnInfo() const { return getArgsBuffer()[0].info; }
+ /// \brief Return true if this function uses inalloca arguments.
+ bool usesInAlloca() const { return ArgStruct; }
+
+ /// \brief Get the struct type used to represent all the arguments in memory.
+ llvm::StructType *getArgStruct() const { return ArgStruct; }
+ void setArgStruct(llvm::StructType *Ty) { ArgStruct = Ty; }
+
void Profile(llvm::FoldingSetNodeID &ID) {
ID.AddInteger(getASTCallingConvention());
ID.AddBoolean(InstanceMethod);
Modified: cfe/trunk/lib/CodeGen/CGCall.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCall.cpp?rev=200597&r1=200596&r2=200597&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGCall.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGCall.cpp Fri Jan 31 18:04:45 2014
@@ -28,7 +28,7 @@
#include "llvm/IR/Attributes.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/InlineAsm.h"
-#include "llvm/MC/SubtargetFeature.h"
+#include "llvm/IR/Intrinsics.h"
#include "llvm/Support/CallSite.h"
#include "llvm/Transforms/Utils/Local.h"
using namespace clang;
@@ -226,6 +226,28 @@ CodeGenTypes::arrangeCXXConstructorDecla
return arrangeLLVMFunctionInfo(resultType, true, argTypes, extInfo, required);
}
+/// Arrange a call to a C++ method, passing the given arguments.
+const CGFunctionInfo &
+CodeGenTypes::arrangeCXXConstructorCall(const CallArgList &args,
+ const CXXConstructorDecl *D,
+ CXXCtorType CtorKind,
+ unsigned ExtraArgs) {
+ // FIXME: Kill copy.
+ SmallVector<CanQualType, 16> ArgTypes;
+ for (CallArgList::const_iterator i = args.begin(), e = args.end(); i != e;
+ ++i)
+ ArgTypes.push_back(Context.getCanonicalParamType(i->Ty));
+
+ CanQual<FunctionProtoType> FPT = GetFormalType(D);
+ RequiredArgs Required = RequiredArgs::forPrototypePlus(FPT, 1 + ExtraArgs);
+ GlobalDecl GD(D, CtorKind);
+ CanQualType ResultType =
+ TheCXXABI.HasThisReturn(GD) ? ArgTypes.front() : Context.VoidTy;
+
+ FunctionType::ExtInfo Info = FPT->getExtInfo();
+ return arrangeLLVMFunctionInfo(ResultType, true, ArgTypes, Info, Required);
+}
+
/// Arrange the argument and result information for a declaration,
/// definition, or call to the given destructor variant. It so
/// happens that all three cases produce the same information.
@@ -505,6 +527,7 @@ CGFunctionInfo *CGFunctionInfo::create(u
FI->Required = required;
FI->HasRegParm = info.getHasRegParm();
FI->RegParm = info.getRegParm();
+ FI->ArgStruct = 0;
FI->NumArgs = argTypes.size();
FI->getArgsBuffer()[0].type = resultType;
for (unsigned i = 0, e = argTypes.size(); i != e; ++i)
@@ -916,6 +939,10 @@ CodeGenTypes::GetFunctionType(const CGFu
resultType = retAI.getCoerceToType();
break;
+ case ABIArgInfo::InAlloca:
+ resultType = llvm::Type::getVoidTy(getLLVMContext());
+ break;
+
case ABIArgInfo::Indirect: {
assert(!retAI.getIndirectAlign() && "Align unused on indirect return.");
resultType = llvm::Type::getVoidTy(getLLVMContext());
@@ -948,6 +975,7 @@ CodeGenTypes::GetFunctionType(const CGFu
switch (argAI.getKind()) {
case ABIArgInfo::Ignore:
+ case ABIArgInfo::InAlloca:
break;
case ABIArgInfo::Indirect: {
@@ -978,6 +1006,10 @@ CodeGenTypes::GetFunctionType(const CGFu
}
}
+ // Add the inalloca struct as the last parameter type.
+ if (llvm::StructType *ArgStruct = FI.getArgStruct())
+ argTypes.push_back(ArgStruct->getPointerTo());
+
bool Erased = FunctionsBeingProcessed.erase(&FI); (void)Erased;
assert(Erased && "Not in set?");
@@ -1103,6 +1135,13 @@ void CodeGenModule::ConstructAttributeLi
case ABIArgInfo::Ignore:
break;
+ case ABIArgInfo::InAlloca: {
+ // inalloca disables readnone and readonly
+ FuncAttrs.removeAttribute(llvm::Attribute::ReadOnly)
+ .removeAttribute(llvm::Attribute::ReadNone);
+ break;
+ }
+
case ABIArgInfo::Indirect: {
llvm::AttrBuilder SRETAttrs;
SRETAttrs.addAttribute(llvm::Attribute::StructRet);
@@ -1187,6 +1226,13 @@ void CodeGenModule::ConstructAttributeLi
// Skip increment, no matching LLVM parameter.
continue;
+ case ABIArgInfo::InAlloca:
+ // inalloca disables readnone and readonly.
+ FuncAttrs.removeAttribute(llvm::Attribute::ReadOnly)
+ .removeAttribute(llvm::Attribute::ReadNone);
+ // Skip increment, no matching LLVM parameter.
+ continue;
+
case ABIArgInfo::Expand: {
SmallVector<llvm::Type*, 8> types;
// FIXME: This is rather inefficient. Do we ever actually need to do
@@ -1202,6 +1248,14 @@ void CodeGenModule::ConstructAttributeLi
PAL.push_back(llvm::AttributeSet::get(getLLVMContext(), Index, Attrs));
++Index;
}
+
+ // Add the inalloca attribute to the trailing inalloca parameter if present.
+ if (FI.usesInAlloca()) {
+ llvm::AttrBuilder Attrs;
+ Attrs.addAttribute(llvm::Attribute::InAlloca);
+ PAL.push_back(llvm::AttributeSet::get(getLLVMContext(), Index, Attrs));
+ }
+
if (FuncAttrs.hasAttributes())
PAL.push_back(llvm::
AttributeSet::get(getLLVMContext(),
@@ -1251,6 +1305,16 @@ void CodeGenFunction::EmitFunctionProlog
// Emit allocs for param decls. Give the LLVM Argument nodes names.
llvm::Function::arg_iterator AI = Fn->arg_begin();
+ // If we're using inalloca, all the memory arguments are GEPs off of the last
+ // parameter, which is a pointer to the complete memory area.
+ llvm::Value *ArgStruct = 0;
+ if (FI.usesInAlloca()) {
+ llvm::Function::arg_iterator EI = Fn->arg_end();
+ --EI;
+ ArgStruct = EI;
+ assert(ArgStruct->getType() == FI.getArgStruct()->getPointerTo());
+ }
+
// Name the struct return argument.
if (CGM.ReturnTypeUsesSRet(FI)) {
AI->setName("agg.result");
@@ -1260,12 +1324,18 @@ void CodeGenFunction::EmitFunctionProlog
++AI;
}
+ // Track if we received the parameter as a pointer (indirect, byval, or
+ // inalloca). If already have a pointer, EmitParmDecl doesn't need to copy it
+ // into a local alloca for us.
+ enum ValOrPointer { HaveValue = 0, HavePointer = 1 };
+ typedef llvm::PointerIntPair<llvm::Value *, 1, ValOrPointer> ValueAndIsPtr;
+ SmallVector<ValueAndIsPtr, 16> ArgVals;
+ ArgVals.reserve(Args.size());
+
// Create a pointer value for every parameter declaration. This usually
// entails copying one or more LLVM IR arguments into an alloca. Don't push
// any cleanups or do anything that might unwind. We do that separately, so
// we can push the cleanups in the correct order for the ABI.
- SmallVector<llvm::Value *, 16> ArgVals;
- ArgVals.reserve(Args.size());
assert(FI.arg_size() == Args.size() &&
"Mismatch between function signature & arguments.");
unsigned ArgNo = 1;
@@ -1284,6 +1354,13 @@ void CodeGenFunction::EmitFunctionProlog
++AI;
switch (ArgI.getKind()) {
+ case ABIArgInfo::InAlloca: {
+ llvm::Value *V = Builder.CreateStructGEP(
+ ArgStruct, ArgI.getInAllocaFieldIndex(), Arg->getName());
+ ArgVals.push_back(ValueAndIsPtr(V, HavePointer));
+ continue; // Don't increment AI!
+ }
+
case ABIArgInfo::Indirect: {
llvm::Value *V = AI;
@@ -1310,6 +1387,7 @@ void CodeGenFunction::EmitFunctionProlog
false);
V = AlignedTemp;
}
+ ArgVals.push_back(ValueAndIsPtr(V, HavePointer));
} else {
// Load scalar value from indirect argument.
CharUnits Alignment = getContext().getTypeAlignInChars(Ty);
@@ -1318,8 +1396,8 @@ void CodeGenFunction::EmitFunctionProlog
if (isPromoted)
V = emitArgumentDemotion(*this, Arg, V);
+ ArgVals.push_back(ValueAndIsPtr(V, HaveValue));
}
- ArgVals.push_back(V);
break;
}
@@ -1360,7 +1438,7 @@ void CodeGenFunction::EmitFunctionProlog
if (V->getType() != LTy)
V = Builder.CreateBitCast(V, LTy);
- ArgVals.push_back(V);
+ ArgVals.push_back(ValueAndIsPtr(V, HaveValue));
break;
}
@@ -1432,8 +1510,10 @@ void CodeGenFunction::EmitFunctionProlog
V = EmitLoadOfScalar(V, false, AlignmentToUse, Ty, Arg->getLocStart());
if (isPromoted)
V = emitArgumentDemotion(*this, Arg, V);
+ ArgVals.push_back(ValueAndIsPtr(V, HaveValue));
+ } else {
+ ArgVals.push_back(ValueAndIsPtr(V, HavePointer));
}
- ArgVals.push_back(V);
continue; // Skip ++AI increment, already done.
}
@@ -1446,7 +1526,7 @@ void CodeGenFunction::EmitFunctionProlog
Alloca->setAlignment(Align.getQuantity());
LValue LV = MakeAddrLValue(Alloca, Ty, Align);
llvm::Function::arg_iterator End = ExpandTypeFromArgs(Ty, LV, AI);
- ArgVals.push_back(Alloca);
+ ArgVals.push_back(ValueAndIsPtr(Alloca, HavePointer));
// Name the arguments used in expansion and increment AI.
unsigned Index = 0;
@@ -1457,10 +1537,12 @@ void CodeGenFunction::EmitFunctionProlog
case ABIArgInfo::Ignore:
// Initialize the local variable appropriately.
- if (!hasScalarEvaluationKind(Ty))
- ArgVals.push_back(CreateMemTemp(Ty));
- else
- ArgVals.push_back(llvm::UndefValue::get(ConvertType(Arg->getType())));
+ if (!hasScalarEvaluationKind(Ty)) {
+ ArgVals.push_back(ValueAndIsPtr(CreateMemTemp(Ty), HavePointer));
+ } else {
+ llvm::Value *U = llvm::UndefValue::get(ConvertType(Arg->getType()));
+ ArgVals.push_back(ValueAndIsPtr(U, HaveValue));
+ }
// Skip increment, no matching LLVM parameter.
continue;
@@ -1468,14 +1550,19 @@ void CodeGenFunction::EmitFunctionProlog
++AI;
}
+
+ if (FI.usesInAlloca())
+ ++AI;
assert(AI == Fn->arg_end() && "Argument mismatch!");
if (getTarget().getCXXABI().areArgsDestroyedLeftToRightInCallee()) {
for (int I = Args.size() - 1; I >= 0; --I)
- EmitParmDecl(*Args[I], ArgVals[I], I + 1);
+ EmitParmDecl(*Args[I], ArgVals[I].getPointer(), ArgVals[I].getInt(),
+ I + 1);
} else {
for (unsigned I = 0, E = Args.size(); I != E; ++I)
- EmitParmDecl(*Args[I], ArgVals[I], I + 1);
+ EmitParmDecl(*Args[I], ArgVals[I].getPointer(), ArgVals[I].getInt(),
+ I + 1);
}
}
@@ -1689,6 +1776,10 @@ void CodeGenFunction::EmitFunctionEpilog
const ABIArgInfo &RetAI = FI.getReturnInfo();
switch (RetAI.getKind()) {
+ case ABIArgInfo::InAlloca:
+ // Do nothing; aggregrates get evaluated directly into the destination.
+ break;
+
case ABIArgInfo::Indirect: {
switch (getEvaluationKind(RetTy)) {
case TEK_Complex: {
@@ -1777,6 +1868,25 @@ void CodeGenFunction::EmitFunctionEpilog
Ret->setDebugLoc(RetDbgLoc);
}
+static bool isInAllocaArgument(CGCXXABI &ABI, QualType type) {
+ const CXXRecordDecl *RD = type->getAsCXXRecordDecl();
+ return RD && ABI.getRecordArgABI(RD) == CGCXXABI::RAA_DirectInMemory;
+}
+
+static AggValueSlot createPlaceholderSlot(CodeGenFunction &CGF, QualType Ty) {
+ // FIXME: Generate IR in one pass, rather than going back and fixing up these
+ // placeholders.
+ llvm::Type *IRTy = CGF.ConvertTypeForMem(Ty);
+ llvm::Value *Placeholder =
+ llvm::UndefValue::get(IRTy->getPointerTo()->getPointerTo());
+ Placeholder = CGF.Builder.CreateLoad(Placeholder);
+ return AggValueSlot::forAddr(Placeholder, CharUnits::Zero(),
+ Ty.getQualifiers(),
+ AggValueSlot::IsNotDestructed,
+ AggValueSlot::DoesNotNeedGCBarriers,
+ AggValueSlot::IsNotAliased);
+}
+
void CodeGenFunction::EmitDelegateCallArg(CallArgList &args,
const VarDecl *param,
SourceLocation loc) {
@@ -1800,6 +1910,20 @@ void CodeGenFunction::EmitDelegateCallAr
return args.add(RValue::get(Builder.CreateLoad(local)), type);
}
+ if (isInAllocaArgument(CGM.getCXXABI(), type)) {
+ AggValueSlot Slot = createPlaceholderSlot(*this, type);
+ Slot.setExternallyDestructed();
+
+ // FIXME: Either emit a copy constructor call, or figure out how to do
+ // guaranteed tail calls with perfect forwarding in LLVM.
+ CGM.ErrorUnsupported(param, "non-trivial argument copy for thunk");
+ EmitNullInitialization(Slot.getAddr(), type);
+
+ RValue RV = Slot.asRValue();
+ args.add(RV, type);
+ return;
+ }
+
args.add(convertTempToRValue(local, type, loc), type);
}
@@ -2031,6 +2155,34 @@ static void emitWritebackArg(CodeGenFunc
args.add(RValue::get(finalArgument), CRE->getType());
}
+void CallArgList::allocateArgumentMemory(CodeGenFunction &CGF) {
+ assert(!StackBase && !StackCleanup.isValid());
+
+ // Save the stack.
+ llvm::Function *F = CGF.CGM.getIntrinsic(llvm::Intrinsic::stacksave);
+ StackBase = CGF.Builder.CreateCall(F, "inalloca.save");
+
+ // Control gets really tied up in landing pads, so we have to spill the
+ // stacksave to an alloca to avoid violating SSA form.
+ // TODO: This is dead if we never emit the cleanup. We should create the
+ // alloca and store lazily on the first cleanup emission.
+ StackBaseMem = CGF.CreateTempAlloca(CGF.Int8PtrTy, "inalloca.spmem");
+ CGF.Builder.CreateStore(StackBase, StackBaseMem);
+ CGF.pushStackRestore(EHCleanup, StackBaseMem);
+ StackCleanup = CGF.EHStack.getInnermostEHScope();
+ assert(StackCleanup.isValid());
+}
+
+void CallArgList::freeArgumentMemory(CodeGenFunction &CGF) const {
+ if (StackBase) {
+ CGF.DeactivateCleanupBlock(StackCleanup, StackBase);
+ llvm::Value *F = CGF.CGM.getIntrinsic(llvm::Intrinsic::stackrestore);
+ // We could load StackBase from StackBaseMem, but in the non-exceptional
+ // case we can skip it.
+ CGF.Builder.CreateCall(F, StackBase);
+ }
+}
+
void CodeGenFunction::EmitCallArgs(CallArgList &Args,
ArrayRef<QualType> ArgTypes,
CallExpr::const_arg_iterator ArgBeg,
@@ -2043,6 +2195,17 @@ void CodeGenFunction::EmitCallArgs(CallA
// We *have* to evaluate arguments from right to left in the MS C++ ABI,
// because arguments are destroyed left to right in the callee.
if (CGM.getTarget().getCXXABI().areArgsDestroyedLeftToRightInCallee()) {
+ // Insert a stack save if we're going to need any inalloca args.
+ bool HasInAllocaArgs = false;
+ for (ArrayRef<QualType>::iterator I = ArgTypes.begin(), E = ArgTypes.end();
+ I != E && !HasInAllocaArgs; ++I)
+ HasInAllocaArgs = isInAllocaArgument(CGM.getCXXABI(), *I);
+ if (HasInAllocaArgs) {
+ assert(getTarget().getTriple().getArch() == llvm::Triple::x86);
+ Args.allocateArgumentMemory(*this);
+ }
+
+ // Evaluate each argument.
size_t CallArgsStart = Args.size();
for (int I = ArgTypes.size() - 1; I >= 0; --I) {
CallExpr::const_arg_iterator Arg = ArgBeg + I;
@@ -2066,6 +2229,25 @@ void CodeGenFunction::EmitCallArgs(CallA
}
}
+namespace {
+
+struct DestroyUnpassedArg : EHScopeStack::Cleanup {
+ DestroyUnpassedArg(llvm::Value *Addr, QualType Ty)
+ : Addr(Addr), Ty(Ty) {}
+
+ llvm::Value *Addr;
+ QualType Ty;
+
+ void Emit(CodeGenFunction &CGF, Flags flags) {
+ const CXXDestructorDecl *Dtor = Ty->getAsCXXRecordDecl()->getDestructor();
+ assert(!Dtor->isTrivial());
+ CGF.EmitCXXDestructorCall(Dtor, Dtor_Complete, /*for vbase*/ false,
+ /*Delegating=*/false, Addr);
+ }
+};
+
+}
+
void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E,
QualType type) {
if (const ObjCIndirectCopyRestoreExpr *CRE
@@ -2088,23 +2270,25 @@ void CodeGenFunction::EmitCallArg(CallAr
// In the Microsoft C++ ABI, aggregate arguments are destructed by the callee.
// However, we still have to push an EH-only cleanup in case we unwind before
// we make it to the call.
- if (HasAggregateEvalKind &&
- CGM.getTarget().getCXXABI().areArgsDestroyedLeftToRightInCallee()) {
- const CXXRecordDecl *RD = type->getAsCXXRecordDecl();
- if (RD && RD->hasNonTrivialDestructor()) {
- AggValueSlot Slot = CreateAggTemp(type, "agg.arg.tmp");
- Slot.setExternallyDestructed();
- EmitAggExpr(E, Slot);
- RValue RV = Slot.asRValue();
- args.add(RV, type);
+ if (HasAggregateEvalKind && args.isUsingInAlloca()) {
+ assert(getTarget().getTriple().getArch() == llvm::Triple::x86);
+ AggValueSlot Slot = createPlaceholderSlot(*this, type);
+ Slot.setExternallyDestructed();
+ EmitAggExpr(E, Slot);
+ RValue RV = Slot.asRValue();
+ args.add(RV, type);
- pushDestroy(EHCleanup, RV.getAggregateAddr(), type, destroyCXXObject,
- /*useEHCleanupForArray*/ true);
+ const CXXRecordDecl *RD = type->getAsCXXRecordDecl();
+ if (RD->hasNonTrivialDestructor()) {
+ // Create a no-op GEP between the placeholder and the cleanup so we can
+ // RAUW it successfully. It also serves as a marker of the first
+ // instruction where the cleanup is active.
+ pushFullExprCleanup<DestroyUnpassedArg>(EHCleanup, Slot.getAddr(), type);
// This unreachable is a temporary marker which will be removed later.
llvm::Instruction *IsActive = Builder.CreateUnreachable();
args.addArgCleanupDeactivation(EHStack.getInnermostEHScope(), IsActive);
- return;
}
+ return;
}
if (HasAggregateEvalKind && isa<ImplicitCastExpr>(E) &&
@@ -2314,6 +2498,20 @@ void CodeGenFunction::ExpandTypeToArgs(Q
}
}
+/// \brief Store a non-aggregate value to an address to initialize it. For
+/// initialization, a non-atomic store will be used.
+static void EmitInitStoreOfNonAggregate(CodeGenFunction &CGF, RValue Src,
+ LValue Dst) {
+ if (Src.isScalar())
+ CGF.EmitStoreOfScalar(Src.getScalarVal(), Dst, /*init=*/true);
+ else
+ CGF.EmitStoreOfComplex(Src.getComplexVal(), Dst, /*init=*/true);
+}
+
+void CodeGenFunction::deferPlaceholderReplacement(llvm::Instruction *Old,
+ llvm::Value *New) {
+ DeferredReplacements.push_back(std::make_pair(Old, New));
+}
RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
llvm::Value *Callee,
@@ -2335,14 +2533,32 @@ RValue CodeGenFunction::EmitCall(const C
cast<llvm::FunctionType>(
cast<llvm::PointerType>(Callee->getType())->getElementType());
+ // If we're using inalloca, insert the allocation after the stack save.
+ // FIXME: Do this earlier rather than hacking it in here!
+ llvm::Value *ArgMemory = 0;
+ if (llvm::StructType *ArgStruct = CallInfo.getArgStruct()) {
+ llvm::AllocaInst *AI = new llvm::AllocaInst(
+ ArgStruct, "argmem", CallArgs.getStackBase()->getNextNode());
+ AI->setUsedWithInAlloca(true);
+ assert(AI->isUsedWithInAlloca() && !AI->isStaticAlloca());
+ ArgMemory = AI;
+ }
+
// If the call returns a temporary with struct return, create a temporary
// alloca to hold the result, unless one is given to us.
- if (CGM.ReturnTypeUsesSRet(CallInfo)) {
- llvm::Value *Value = ReturnValue.getValue();
- if (!Value)
- Value = CreateMemTemp(RetTy);
- Args.push_back(Value);
- checkArgMatches(Value, IRArgNo, IRFuncTy);
+ llvm::Value *SRetPtr = 0;
+ if (CGM.ReturnTypeUsesSRet(CallInfo) || RetAI.isInAlloca()) {
+ SRetPtr = ReturnValue.getValue();
+ if (!SRetPtr)
+ SRetPtr = CreateMemTemp(RetTy);
+ if (CGM.ReturnTypeUsesSRet(CallInfo)) {
+ Args.push_back(SRetPtr);
+ checkArgMatches(SRetPtr, IRArgNo, IRFuncTy);
+ } else {
+ llvm::Value *Addr =
+ Builder.CreateStructGEP(ArgMemory, RetAI.getInAllocaFieldIndex());
+ Builder.CreateStore(SRetPtr, Addr);
+ }
}
assert(CallInfo.arg_size() == CallArgs.size() &&
@@ -2362,6 +2578,28 @@ RValue CodeGenFunction::EmitCall(const C
}
switch (ArgInfo.getKind()) {
+ case ABIArgInfo::InAlloca: {
+ assert(getTarget().getTriple().getArch() == llvm::Triple::x86);
+ if (RV.isAggregate()) {
+ // Replace the placeholder with the appropriate argument slot GEP.
+ llvm::Instruction *Placeholder =
+ cast<llvm::Instruction>(RV.getAggregateAddr());
+ CGBuilderTy::InsertPoint IP = Builder.saveIP();
+ Builder.SetInsertPoint(Placeholder);
+ llvm::Value *Addr = Builder.CreateStructGEP(
+ ArgMemory, ArgInfo.getInAllocaFieldIndex());
+ Builder.restoreIP(IP);
+ deferPlaceholderReplacement(Placeholder, Addr);
+ } else {
+ // Store the RValue into the argument struct.
+ llvm::Value *Addr =
+ Builder.CreateStructGEP(ArgMemory, ArgInfo.getInAllocaFieldIndex());
+ LValue argLV = MakeAddrLValue(Addr, I->Ty, TypeAlign);
+ EmitInitStoreOfNonAggregate(*this, RV, argLV);
+ }
+ break; // Don't increment IRArgNo!
+ }
+
case ABIArgInfo::Indirect: {
if (RV.isScalar() || RV.isComplex()) {
// Make a temporary alloca to pass the argument.
@@ -2370,13 +2608,8 @@ RValue CodeGenFunction::EmitCall(const C
AI->setAlignment(ArgInfo.getIndirectAlign());
Args.push_back(AI);
- LValue argLV =
- MakeAddrLValue(Args.back(), I->Ty, TypeAlign);
-
- if (RV.isScalar())
- EmitStoreOfScalar(RV.getScalarVal(), argLV, /*init*/ true);
- else
- EmitStoreOfComplex(RV.getComplexVal(), argLV, /*init*/ true);
+ LValue argLV = MakeAddrLValue(Args.back(), I->Ty, TypeAlign);
+ EmitInitStoreOfNonAggregate(*this, RV, argLV);
// Validate argument match.
checkArgMatches(AI, IRArgNo, IRFuncTy);
@@ -2449,11 +2682,7 @@ RValue CodeGenFunction::EmitCall(const C
if (RV.isScalar() || RV.isComplex()) {
SrcPtr = CreateMemTemp(I->Ty, "coerce");
LValue SrcLV = MakeAddrLValue(SrcPtr, I->Ty, TypeAlign);
- if (RV.isScalar()) {
- EmitStoreOfScalar(RV.getScalarVal(), SrcLV, /*init*/ true);
- } else {
- EmitStoreOfComplex(RV.getComplexVal(), SrcLV, /*init*/ true);
- }
+ EmitInitStoreOfNonAggregate(*this, RV, SrcLV);
} else
SrcPtr = RV.getAggregateAddr();
@@ -2519,6 +2748,34 @@ RValue CodeGenFunction::EmitCall(const C
}
}
+ if (ArgMemory) {
+ llvm::Value *Arg = ArgMemory;
+ llvm::Type *LastParamTy =
+ IRFuncTy->getParamType(IRFuncTy->getNumParams() - 1);
+ if (Arg->getType() != LastParamTy) {
+#ifndef NDEBUG
+ // Assert that these structs have equivalent element types.
+ llvm::StructType *FullTy = CallInfo.getArgStruct();
+ llvm::StructType *Prefix = cast<llvm::StructType>(
+ cast<llvm::PointerType>(LastParamTy)->getElementType());
+
+ // For variadic functions, the caller might supply a larger struct than
+ // the callee expects, and that's OK.
+ assert(Prefix->getNumElements() == FullTy->getNumElements() ||
+ (CallInfo.isVariadic() &&
+ Prefix->getNumElements() <= FullTy->getNumElements()));
+
+ for (llvm::StructType::element_iterator PI = Prefix->element_begin(),
+ PE = Prefix->element_end(),
+ FI = FullTy->element_begin();
+ PI != PE; ++PI, ++FI)
+ assert(*PI == *FI);
+#endif
+ Arg = Builder.CreateBitCast(Arg, LastParamTy);
+ }
+ Args.push_back(Arg);
+ }
+
if (!CallArgs.getCleanupsToDeactivate().empty())
deactivateArgCleanupsBeforeCall(*this, CallArgs);
@@ -2608,9 +2865,14 @@ RValue CodeGenFunction::EmitCall(const C
if (CallArgs.hasWritebacks())
emitWritebacks(*this, CallArgs);
+ // The stack cleanup for inalloca arguments has to run out of the normal
+ // lexical order, so deactivate it and run it manually here.
+ CallArgs.freeArgumentMemory(*this);
+
switch (RetAI.getKind()) {
+ case ABIArgInfo::InAlloca:
case ABIArgInfo::Indirect:
- return convertTempToRValue(Args[0], RetTy, SourceLocation());
+ return convertTempToRValue(SRetPtr, RetTy, SourceLocation());
case ABIArgInfo::Ignore:
// If we are ignoring an argument that had a result, make sure to
Modified: cfe/trunk/lib/CodeGen/CGCall.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCall.h?rev=200597&r1=200596&r2=200597&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGCall.h (original)
+++ cfe/trunk/lib/CodeGen/CGCall.h Fri Jan 31 18:04:45 2014
@@ -56,6 +56,8 @@ namespace CodeGen {
class CallArgList :
public SmallVector<CallArg, 16> {
public:
+ CallArgList() : StackBase(0), StackBaseMem(0) {}
+
struct Writeback {
/// The original argument. Note that the argument l-value
/// is potentially null.
@@ -113,6 +115,14 @@ namespace CodeGen {
return CleanupsToDeactivate;
}
+ void allocateArgumentMemory(CodeGenFunction &CGF);
+ llvm::Instruction *getStackBase() const { return StackBase; }
+ void freeArgumentMemory(CodeGenFunction &CGF) const;
+
+ /// \brief Returns if we're using an inalloca struct to pass arguments in
+ /// memory.
+ bool isUsingInAlloca() const { return StackBase; }
+
private:
SmallVector<Writeback, 1> Writebacks;
@@ -120,6 +130,17 @@ namespace CodeGen {
/// is used to cleanup objects that are owned by the callee once the call
/// occurs.
SmallVector<CallArgCleanup, 1> CleanupsToDeactivate;
+
+ /// The stacksave call. It dominates all of the argument evaluation.
+ llvm::CallInst *StackBase;
+
+ /// The alloca holding the stackbase. We need it to maintain SSA form.
+ llvm::AllocaInst *StackBaseMem;
+
+ /// The iterator pointing to the stack restore cleanup. We manually run and
+ /// deactivate this cleanup after the call in the unexceptional case because
+ /// it doesn't run in the normal order.
+ EHScopeStack::stable_iterator StackCleanup;
};
/// FunctionArgList - Type for representing both the decl and type
Modified: cfe/trunk/lib/CodeGen/CGClass.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGClass.cpp?rev=200597&r1=200596&r2=200597&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGClass.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGClass.cpp Fri Jan 31 18:04:45 2014
@@ -1714,9 +1714,8 @@ CodeGenFunction::EmitCXXConstructorCall(
// Emit the call.
llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, Type);
- RequiredArgs Required = RequiredArgs::forPrototypePlus(FPT, 1 + ExtraArgs);
const CGFunctionInfo &Info =
- CGM.getTypes().arrangeCXXMethodCall(Args, FPT, Required);
+ CGM.getTypes().arrangeCXXConstructorCall(Args, D, Type, ExtraArgs);
EmitCall(Info, Callee, ReturnValueSlot(), Args, D);
}
Modified: cfe/trunk/lib/CodeGen/CGDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDecl.cpp?rev=200597&r1=200596&r2=200597&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGDecl.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGDecl.cpp Fri Jan 31 18:04:45 2014
@@ -944,7 +944,7 @@ CodeGenFunction::EmitAutoVarAlloca(const
// Push a cleanup block and restore the stack there.
// FIXME: in general circumstances, this should be an EH cleanup.
- EHStack.pushCleanup<CallStackRestore>(NormalCleanup, Stack);
+ pushStackRestore(NormalCleanup, Stack);
}
llvm::Value *elementCount;
@@ -1344,6 +1344,10 @@ void CodeGenFunction::pushDestroy(Cleanu
destroyer, useEHCleanupForArray);
}
+void CodeGenFunction::pushStackRestore(CleanupKind Kind, llvm::Value *SPMem) {
+ EHStack.pushCleanup<CallStackRestore>(Kind, SPMem);
+}
+
void CodeGenFunction::pushLifetimeExtendedDestroy(
CleanupKind cleanupKind, llvm::Value *addr, QualType type,
Destroyer *destroyer, bool useEHCleanupForArray) {
@@ -1603,7 +1607,7 @@ namespace {
/// Emit an alloca (or GlobalValue depending on target)
/// for the specified parameter and set up LocalDeclMap.
void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg,
- unsigned ArgNo) {
+ bool ArgIsPointer, unsigned ArgNo) {
// FIXME: Why isn't ImplicitParamDecl a ParmVarDecl?
assert((isa<ParmVarDecl>(D) || isa<ImplicitParamDecl>(D)) &&
"Invalid argument to EmitParmDecl");
@@ -1641,30 +1645,32 @@ void CodeGenFunction::EmitParmDecl(const
}
llvm::Value *DeclPtr;
- bool HasNonScalarEvalKind = !CodeGenFunction::hasScalarEvaluationKind(Ty);
- // If this is an aggregate or variable sized value, reuse the input pointer.
- if (HasNonScalarEvalKind || !Ty->isConstantSizeType()) {
+ bool DoStore = false;
+ bool IsScalar = hasScalarEvaluationKind(Ty);
+ CharUnits Align = getContext().getDeclAlign(&D);
+ // If we already have a pointer to the argument, reuse the input pointer.
+ if (ArgIsPointer) {
+ assert(isa<llvm::PointerType>(Arg->getType()));
DeclPtr = Arg;
// Push a destructor cleanup for this parameter if the ABI requires it.
- if (HasNonScalarEvalKind &&
+ if (!IsScalar &&
getTarget().getCXXABI().areArgsDestroyedLeftToRightInCallee()) {
- if (const CXXRecordDecl *RD = Ty->getAsCXXRecordDecl()) {
- if (RD->hasNonTrivialDestructor())
- pushDestroy(QualType::DK_cxx_destructor, DeclPtr, Ty);
- }
+ const CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
+ if (RD && RD->hasNonTrivialDestructor())
+ pushDestroy(QualType::DK_cxx_destructor, DeclPtr, Ty);
}
} else {
// Otherwise, create a temporary to hold the value.
llvm::AllocaInst *Alloc = CreateTempAlloca(ConvertTypeForMem(Ty),
D.getName() + ".addr");
- CharUnits Align = getContext().getDeclAlign(&D);
Alloc->setAlignment(Align.getQuantity());
DeclPtr = Alloc;
+ DoStore = true;
+ }
- bool doStore = true;
-
+ LValue lv = MakeAddrLValue(DeclPtr, Ty, Align);
+ if (IsScalar) {
Qualifiers qs = Ty.getQualifiers();
- LValue lv = MakeAddrLValue(DeclPtr, Ty, Align);
if (Qualifiers::ObjCLifetime lt = qs.getObjCLifetime()) {
// We honor __attribute__((ns_consumed)) for types with lifetime.
// For __strong, it's handled by just skipping the initial retain;
@@ -1693,7 +1699,7 @@ void CodeGenFunction::EmitParmDecl(const
llvm::Value *Null = CGM.EmitNullConstant(D.getType());
EmitStoreOfScalar(Null, lv, /* isInitialization */ true);
EmitARCStoreStrongCall(lv.getAddress(), Arg, true);
- doStore = false;
+ DoStore = false;
}
else
// Don't use objc_retainBlock for block pointers, because we
@@ -1712,19 +1718,19 @@ void CodeGenFunction::EmitParmDecl(const
if (lt == Qualifiers::OCL_Weak) {
EmitARCInitWeak(DeclPtr, Arg);
- doStore = false; // The weak init is a store, no need to do two.
+ DoStore = false; // The weak init is a store, no need to do two.
}
}
// Enter the cleanup scope.
EmitAutoVarWithLifetime(*this, D, DeclPtr, lt);
}
-
- // Store the initial value into the alloca.
- if (doStore)
- EmitStoreOfScalar(Arg, lv, /* isInitialization */ true);
}
+ // Store the initial value into the alloca.
+ if (DoStore)
+ EmitStoreOfScalar(Arg, lv, /* isInitialization */ true);
+
llvm::Value *&DMEntry = LocalDeclMap[&D];
assert(DMEntry == 0 && "Decl already exists in localdeclmap!");
DMEntry = DeclPtr;
Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.cpp?rev=200597&r1=200596&r2=200597&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.cpp (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.cpp Fri Jan 31 18:04:45 2014
@@ -276,6 +276,14 @@ void CodeGenFunction::FinishFunction(Sou
if (CGM.getCodeGenOpts().EmitDeclMetadata)
EmitDeclMetadata();
+
+ for (SmallVectorImpl<std::pair<llvm::Instruction *, llvm::Value *> >::iterator
+ I = DeferredReplacements.begin(),
+ E = DeferredReplacements.end();
+ I != E; ++I) {
+ I->first->replaceAllUsesWith(I->second);
+ I->first->eraseFromParent();
+ }
}
/// ShouldInstrumentFunction - Return true if the current function should be
@@ -592,6 +600,14 @@ void CodeGenFunction::StartFunction(Glob
// Indirect aggregate return; emit returned value directly into sret slot.
// This reduces code size, and affects correctness in C++.
ReturnValue = CurFn->arg_begin();
+ } else if (CurFnInfo->getReturnInfo().getKind() == ABIArgInfo::InAlloca &&
+ !hasScalarEvaluationKind(CurFnInfo->getReturnType())) {
+ // Load the sret pointer from the argument struct and return into that.
+ unsigned Idx = CurFnInfo->getReturnInfo().getInAllocaFieldIndex();
+ llvm::Function::arg_iterator EI = CurFn->arg_end();
+ --EI;
+ llvm::Value *Addr = Builder.CreateStructGEP(EI, Idx);
+ ReturnValue = Builder.CreateLoad(Addr, "agg.result");
} else {
ReturnValue = CreateIRTemp(RetTy, "retval");
Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=200597&r1=200596&r2=200597&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Fri Jan 31 18:04:45 2014
@@ -1037,6 +1037,7 @@ public:
void pushLifetimeExtendedDestroy(CleanupKind kind, llvm::Value *addr,
QualType type, Destroyer *destroyer,
bool useEHCleanupForArray);
+ void pushStackRestore(CleanupKind kind, llvm::Value *SPMem);
void emitDestroy(llvm::Value *addr, QualType type, Destroyer *destroyer,
bool useEHCleanupForArray);
llvm::Function *generateDestroyHelper(llvm::Constant *addr, QualType type,
@@ -1398,6 +1399,10 @@ public:
AggValueSlot::IsNotAliased);
}
+ /// CreateInAllocaTmp - Create a temporary memory object for the given
+ /// aggregate type.
+ AggValueSlot CreateInAllocaTmp(QualType T, const Twine &Name = "inalloca");
+
/// Emit a cast to void* in the appropriate address space.
llvm::Value *EmitCastToVoidPtr(llvm::Value *value);
@@ -1785,7 +1790,8 @@ public:
llvm::GlobalValue::LinkageTypes Linkage);
/// EmitParmDecl - Emit a ParmVarDecl or an ImplicitParamDecl.
- void EmitParmDecl(const VarDecl &D, llvm::Value *Arg, unsigned ArgNo);
+ void EmitParmDecl(const VarDecl &D, llvm::Value *Arg, bool ArgIsPointer,
+ unsigned ArgNo);
/// protectFromPeepholes - Protect a value that we're intending to
/// store to the side, but which will probably be used later, from
@@ -2490,6 +2496,11 @@ private:
llvm::MDNode *getRangeForLoadFromType(QualType Ty);
void EmitReturnOfRValue(RValue RV, QualType Ty);
+ void deferPlaceholderReplacement(llvm::Instruction *Old, llvm::Value *New);
+
+ llvm::SmallVector<std::pair<llvm::Instruction *, llvm::Value *>, 4>
+ DeferredReplacements;
+
/// ExpandTypeFromArgs - Reconstruct a structure of type \arg Ty
/// from function arguments into \arg Dst. See ABIArgInfo::Expand.
///
Modified: cfe/trunk/lib/CodeGen/CodeGenTypes.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenTypes.h?rev=200597&r1=200596&r2=200597&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenTypes.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenTypes.h Fri Jan 31 18:04:45 2014
@@ -188,6 +188,10 @@ public:
const CGFunctionInfo &arrangeCXXConstructorDeclaration(
const CXXConstructorDecl *D,
CXXCtorType Type);
+ const CGFunctionInfo &arrangeCXXConstructorCall(const CallArgList &Args,
+ const CXXConstructorDecl *D,
+ CXXCtorType CtorKind,
+ unsigned ExtraArgs);
const CGFunctionInfo &arrangeCXXDestructor(const CXXDestructorDecl *D,
CXXDtorType Type);
Modified: cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp?rev=200597&r1=200596&r2=200597&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp (original)
+++ cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp Fri Jan 31 18:04:45 2014
@@ -45,8 +45,14 @@ public:
}
RecordArgABI getRecordArgABI(const CXXRecordDecl *RD) const {
- if (RD->hasNonTrivialCopyConstructor() || RD->hasNonTrivialDestructor())
- return RAA_DirectInMemory;
+ if (RD->hasNonTrivialCopyConstructor() || RD->hasNonTrivialDestructor()) {
+ llvm::Triple::ArchType Arch = CGM.getTarget().getTriple().getArch();
+ if (Arch == llvm::Triple::x86)
+ return RAA_DirectInMemory;
+ // On x64, pass non-trivial records indirectly.
+ // FIXME: Test other Windows architectures.
+ return RAA_Indirect;
+ }
return RAA_Default;
}
Modified: cfe/trunk/lib/CodeGen/TargetInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/TargetInfo.cpp?rev=200597&r1=200596&r2=200597&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/TargetInfo.cpp (original)
+++ cfe/trunk/lib/CodeGen/TargetInfo.cpp Fri Jan 31 18:04:45 2014
@@ -114,6 +114,9 @@ void ABIArgInfo::dump() const {
case Ignore:
OS << "Ignore";
break;
+ case InAlloca:
+ OS << "InAlloca Offset=" << getInAllocaFieldIndex();
+ break;
case Indirect:
OS << "Indirect Align=" << getIndirectAlign()
<< " ByVal=" << getIndirectByVal()
@@ -532,6 +535,8 @@ struct CCState {
unsigned CC;
unsigned FreeRegs;
+ unsigned StackOffset;
+ bool UseInAlloca;
};
/// X86_32ABIInfo - The X86-32 ABI information.
@@ -570,6 +575,14 @@ class X86_32ABIInfo : public ABIInfo {
ABIArgInfo classifyArgumentType(QualType RetTy, CCState &State) const;
bool shouldUseInReg(QualType Ty, CCState &State, bool &NeedsPadding) const;
+ /// \brief Rewrite the function info so that all memory arguments use
+ /// inalloca.
+ void rewriteWithInAlloca(CGFunctionInfo &FI) const;
+
+ void addFieldToArgStruct(SmallVector<llvm::Type *, 6> &FrameFields,
+ unsigned &StackOffset, ABIArgInfo &Info,
+ QualType Type) const;
+
public:
virtual void computeInfo(CGFunctionInfo &FI) const;
@@ -831,15 +844,12 @@ ABIArgInfo X86_32ABIInfo::getIndirectRes
unsigned TypeAlign = getContext().getTypeAlign(Ty) / 8;
unsigned StackAlign = getTypeStackAlignInBytes(Ty, TypeAlign);
if (StackAlign == 0)
- return ABIArgInfo::getIndirect(4);
+ return ABIArgInfo::getIndirect(4, /*ByVal=*/true);
// If the stack alignment is less than the type alignment, realign the
// argument.
- if (StackAlign < TypeAlign)
- return ABIArgInfo::getIndirect(StackAlign, /*ByVal=*/true,
- /*Realign=*/true);
-
- return ABIArgInfo::getIndirect(StackAlign);
+ bool Realign = TypeAlign > StackAlign;
+ return ABIArgInfo::getIndirect(StackAlign, /*ByVal=*/true, Realign);
}
X86_32ABIInfo::Class X86_32ABIInfo::classify(QualType Ty) const {
@@ -897,17 +907,24 @@ bool X86_32ABIInfo::shouldUseInReg(QualT
return true;
}
-ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty, CCState &State) const {
+ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty,
+ CCState &State) const {
// FIXME: Set alignment on indirect arguments.
if (isAggregateTypeForABI(Ty)) {
if (const RecordType *RT = Ty->getAs<RecordType>()) {
+ // Check with the C++ ABI first.
+ CGCXXABI::RecordArgABI RAA = getRecordArgABI(RT, getCXXABI());
+ if (RAA == CGCXXABI::RAA_Indirect) {
+ return getIndirectResult(Ty, false, State);
+ } else if (RAA == CGCXXABI::RAA_DirectInMemory) {
+ // The field index doesn't matter, we'll fix it up later.
+ return ABIArgInfo::getInAlloca(/*FieldIndex=*/0);
+ }
+
+ // Structs are always byval on win32, regardless of what they contain.
if (IsWin32StructABI)
return getIndirectResult(Ty, true, State);
- if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(RT, getCXXABI()))
- return getIndirectResult(Ty, RAA == CGCXXABI::RAA_DirectInMemory,
- State);
-
// Structures with flexible arrays are always indirect.
if (RT->getDecl()->hasFlexibleArrayMember())
return getIndirectResult(Ty, true, State);
@@ -994,9 +1011,87 @@ void X86_32ABIInfo::computeInfo(CGFuncti
FI.getReturnInfo().isIndirect())
FI.setEffectiveCallingConvention(llvm::CallingConv::X86_CDeclMethod);
+ bool UsedInAlloca = false;
for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
- it != ie; ++it)
+ it != ie; ++it) {
it->info = classifyArgumentType(it->type, State);
+ UsedInAlloca |= (it->info.getKind() == ABIArgInfo::InAlloca);
+ }
+
+ // If we needed to use inalloca for any argument, do a second pass and rewrite
+ // all the memory arguments to use inalloca.
+ if (UsedInAlloca)
+ rewriteWithInAlloca(FI);
+}
+
+void
+X86_32ABIInfo::addFieldToArgStruct(SmallVector<llvm::Type *, 6> &FrameFields,
+ unsigned &StackOffset,
+ ABIArgInfo &Info, QualType Type) const {
+ // Insert padding bytes to respect alignment. For x86_32, each argument is 4
+ // byte aligned.
+ unsigned Align = 4U;
+ if (Info.getKind() == ABIArgInfo::Indirect && Info.getIndirectByVal())
+ Align = std::max(Align, Info.getIndirectAlign());
+ if (StackOffset & (Align - 1)) {
+ unsigned OldOffset = StackOffset;
+ StackOffset = llvm::RoundUpToAlignment(StackOffset, Align);
+ unsigned NumBytes = StackOffset - OldOffset;
+ assert(NumBytes);
+ llvm::Type *Ty = llvm::Type::getInt8Ty(getVMContext());
+ Ty = llvm::ArrayType::get(Ty, NumBytes);
+ FrameFields.push_back(Ty);
+ }
+
+ Info = ABIArgInfo::getInAlloca(FrameFields.size());
+ FrameFields.push_back(CGT.ConvertTypeForMem(Type));
+ StackOffset += getContext().getTypeSizeInChars(Type).getQuantity();
+}
+
+void X86_32ABIInfo::rewriteWithInAlloca(CGFunctionInfo &FI) const {
+ assert(IsWin32StructABI && "inalloca only supported on win32");
+
+ // Build a packed struct type for all of the arguments in memory.
+ SmallVector<llvm::Type *, 6> FrameFields;
+
+ unsigned StackOffset = 0;
+
+ // Put the sret parameter into the inalloca struct if it's in memory.
+ ABIArgInfo &Ret = FI.getReturnInfo();
+ if (Ret.isIndirect() && !Ret.getInReg()) {
+ CanQualType PtrTy = getContext().getPointerType(FI.getReturnType());
+ addFieldToArgStruct(FrameFields, StackOffset, Ret, PtrTy);
+ }
+
+ // Skip the 'this' parameter in ecx.
+ CGFunctionInfo::arg_iterator I = FI.arg_begin(), E = FI.arg_end();
+ if (FI.getCallingConvention() == llvm::CallingConv::X86_ThisCall)
+ ++I;
+
+ // Put arguments passed in memory into the struct.
+ for (; I != E; ++I) {
+
+ // Leave ignored and inreg arguments alone.
+ switch (I->info.getKind()) {
+ case ABIArgInfo::Indirect:
+ assert(I->info.getIndirectByVal());
+ break;
+ case ABIArgInfo::Ignore:
+ continue;
+ case ABIArgInfo::Direct:
+ case ABIArgInfo::Extend:
+ if (I->info.getInReg())
+ continue;
+ break;
+ default:
+ break;
+ }
+
+ addFieldToArgStruct(FrameFields, StackOffset, I->info, I->type);
+ }
+
+ FI.setArgStruct(llvm::StructType::get(getVMContext(), FrameFields,
+ /*isPacked=*/true));
}
llvm::Value *X86_32ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
@@ -5413,6 +5508,7 @@ llvm::Value *SparcV9ABIInfo::EmitVAArg(l
switch (AI.getKind()) {
case ABIArgInfo::Expand:
+ case ABIArgInfo::InAlloca:
llvm_unreachable("Unsupported ABI kind for va_arg");
case ABIArgInfo::Extend:
@@ -5499,6 +5595,7 @@ llvm::Value *XCoreABIInfo::EmitVAArg(llv
uint64_t ArgSize = 0;
switch (AI.getKind()) {
case ABIArgInfo::Expand:
+ case ABIArgInfo::InAlloca:
llvm_unreachable("Unsupported ABI kind for va_arg");
case ABIArgInfo::Ignore:
Val = llvm::UndefValue::get(ArgPtrTy);
Modified: cfe/trunk/test/CodeGenCXX/copy-constructor-elim.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/copy-constructor-elim.cpp?rev=200597&r1=200596&r2=200597&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/copy-constructor-elim.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/copy-constructor-elim.cpp Fri Jan 31 18:04:45 2014
@@ -1,6 +1,9 @@
-// RUN: %clang_cc1 -emit-llvm -o %t %s
-// RUN: not grep "_ZN1CC1ERK1C" %t
-// RUN: not grep "_ZN1SC1ERK1S" %t
+// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK
+// RUN: %clang_cc1 -triple %ms_abi_triple -emit-llvm -o - %s | FileCheck %s -check-prefix MS
+// CHECK-NOT: _ZN1CC1ERK1C
+// CHECK-NOT: _ZN1SC1ERK1S
+// MS-NOT: ?0C@@QAE at ABV0
+// MS-NOT: ?0S@@QAE at ABV0
extern "C" int printf(...);
Modified: cfe/trunk/test/CodeGenCXX/microsoft-abi-arg-order.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-arg-order.cpp?rev=200597&r1=200596&r2=200597&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/microsoft-abi-arg-order.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/microsoft-abi-arg-order.cpp Fri Jan 31 18:04:45 2014
@@ -12,7 +12,10 @@ void foo(A a, A b, A c) {
// Order of destruction should be left to right.
//
// CHECK-LABEL: define void @"\01?foo@@YAXUA@@00 at Z"
-// CHECK: ({{.*}} %[[a:.*]], {{.*}} %[[b:.*]], {{.*}} %[[c:.*]])
+// CHECK: ([[argmem_ty:<{ %struct.A, %struct.A, %struct.A }>]]* inalloca)
+// CHECK: %[[a:[^ ]*]] = getelementptr inbounds [[argmem_ty]]* %0, i32 0, i32 0
+// CHECK: %[[b:[^ ]*]] = getelementptr inbounds [[argmem_ty]]* %0, i32 0, i32 1
+// CHECK: %[[c:[^ ]*]] = getelementptr inbounds [[argmem_ty]]* %0, i32 0, i32 2
// CHECK: call x86_thiscallcc void @"\01??1A@@QAE at XZ"(%struct.A* %[[a]])
// CHECK: call x86_thiscallcc void @"\01??1A@@QAE at XZ"(%struct.A* %[[b]])
// CHECK: call x86_thiscallcc void @"\01??1A@@QAE at XZ"(%struct.A* %[[c]])
@@ -27,10 +30,16 @@ void call_foo() {
// things as we unwind.
//
// CHECK-LABEL: define void @"\01?call_foo@@YAXXZ"()
-// CHECK: call x86_thiscallcc %struct.A* @"\01??0A@@QAE at H@Z"(%struct.A* %[[arg3:.*]], i32 3)
-// CHECK: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE at H@Z"(%struct.A* %[[arg2:.*]], i32 2)
-// CHECK: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE at H@Z"(%struct.A* %[[arg1:.*]], i32 1)
-// CHECK: call void @"\01?foo@@YAXUA@@00 at Z"({{.*}} %[[arg1]], {{.*}} %[[arg2]], {{.*}} %[[arg3]])
+// CHECK: call i8* @llvm.stacksave()
+// CHECK: %[[argmem:[^ ]*]] = alloca [[argmem_ty]], inalloca
+// CHECK: %[[arg3:[^ ]*]] = getelementptr inbounds [[argmem_ty]]* %[[argmem]], i32 0, i32 2
+// CHECK: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE at H@Z"(%struct.A* %[[arg3]], i32 3)
+// CHECK: %[[arg2:[^ ]*]] = getelementptr inbounds [[argmem_ty]]* %[[argmem]], i32 0, i32 1
+// CHECK: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE at H@Z"(%struct.A* %[[arg2]], i32 2)
+// CHECK: %[[arg1:[^ ]*]] = getelementptr inbounds [[argmem_ty]]* %[[argmem]], i32 0, i32 0
+// CHECK: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE at H@Z"(%struct.A* %[[arg1]], i32 1)
+// CHECK: invoke void @"\01?foo@@YAXUA@@00 at Z"([[argmem_ty]]* inalloca %[[argmem]])
+// CHECK: call void @llvm.stackrestore
// CHECK: ret void
//
// lpad2:
Added: cfe/trunk/test/CodeGenCXX/microsoft-abi-byval-sret.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-byval-sret.cpp?rev=200597&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/microsoft-abi-byval-sret.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/microsoft-abi-byval-sret.cpp Fri Jan 31 18:04:45 2014
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - -triple=i686-pc-win32 -mconstructor-aliases -fno-rtti | FileCheck %s
+
+struct A {
+ A() : a(42) {}
+ A(const A &o) : a(o.a) {}
+ ~A() {}
+ int a;
+ A foo(A o);
+};
+
+A A::foo(A x) {
+ A y(*this);
+ y.a += x.a;
+ return y;
+}
+
+// CHECK: define x86_thiscallcc void @"\01?foo at A@@QAE?AU1 at U1@@Z"
+// CHECK: (%struct.A* %this, <{ %struct.A*, %struct.A }>* inalloca)
+
+int main() {
+ A x;
+ A y = x.foo(x);
+}
+
+// CHECK: call x86_thiscallcc void @"\01?foo at A@@QAE?AU1 at U1@@Z"
+// CHECK: (%struct.A* %{{[^,]*}}, <{ %struct.A*, %struct.A }>* inalloca %{{[^,]*}})
Added: cfe/trunk/test/CodeGenCXX/microsoft-abi-byval-vararg.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-byval-vararg.cpp?rev=200597&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/microsoft-abi-byval-vararg.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/microsoft-abi-byval-vararg.cpp Fri Jan 31 18:04:45 2014
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - -triple=i686-pc-win32 -mconstructor-aliases -fno-rtti | FileCheck %s
+
+#include <stdarg.h>
+
+struct A {
+ A(int a) : a(a) {}
+ A(const A &o) : a(o.a) {}
+ ~A() {}
+ int a;
+};
+
+int foo(A a, ...) {
+ va_list ap;
+ va_start(ap, a);
+ int sum = 0;
+ for (int i = 0; i < a.a; ++i)
+ sum += va_arg(ap, int);
+ va_end(ap);
+ return sum;
+}
+
+int main() {
+ return foo(A(3), 1, 2, 3);
+}
+// CHECK-LABEL: define i32 @main()
+// CHECK: %[[argmem_cast:[^ ]*]] = bitcast <{ %struct.A, i32, i32, i32 }>* %argmem to <{ %struct.A }>*
+// CHECK: call i32 (<{ %struct.A }>*, ...)* @"\01?foo@@YAHUA@@ZZ"(<{ %struct.A }>* inalloca %[[argmem_cast]])
Modified: cfe/trunk/test/CodeGenCXX/microsoft-abi-exceptions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-exceptions.cpp?rev=200597&r1=200596&r2=200597&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/microsoft-abi-exceptions.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/microsoft-abi-exceptions.cpp Fri Jan 31 18:04:45 2014
@@ -14,17 +14,21 @@ void HasEHCleanup() {
}
// With exceptions, we need to clean up at least one of these temporaries.
-// WIN32: define void @"\01?HasEHCleanup@@YAXXZ"() {{.*}} {
-// First one doesn't have any cleanups, no need for invoke.
-// WIN32: call void @"\01?getA@@YA?AUA@@XZ"(%struct.A* sret %{{.*}})
+// WIN32-LABEL: define void @"\01?HasEHCleanup@@YAXXZ"() {{.*}} {
+// WIN32: %[[base:.*]] = call i8* @llvm.stacksave()
+// If this call throws, we have to restore the stack.
+// WIN32: invoke void @"\01?getA@@YA?AUA@@XZ"(%struct.A* sret %{{.*}})
// If this call throws, we have to cleanup the first temporary.
// WIN32: invoke void @"\01?getA@@YA?AUA@@XZ"(%struct.A* sret %{{.*}})
-// If this call throws, we already popped our cleanups
-// WIN32: call i32 @"\01?TakesTwo@@YAHUA@@0 at Z"
+// If this call throws, we have to cleanup the stacksave.
+// WIN32: invoke i32 @"\01?TakesTwo@@YAHUA@@0 at Z"
+// WIN32: call void @llvm.stackrestore(i8* %[[base]])
// WIN32: ret void
//
// There should be one dtor call for unwinding from the second getA.
// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE at XZ"
+// WIN32-NOT: @"\01??1A@@QAE at XZ"
+// WIN32: call void @llvm.stackrestore
// WIN32: }
void TakeRef(const A &a);
@@ -32,20 +36,28 @@ int HasDeactivatedCleanups() {
return TakesTwo((TakeRef(A()), A()), (TakeRef(A()), A()));
}
-// WIN32: define i32 @"\01?HasDeactivatedCleanups@@YAHXZ"() {{.*}} {
+// WIN32-LABEL: define i32 @"\01?HasDeactivatedCleanups@@YAHXZ"() {{.*}} {
// WIN32: %[[isactive:.*]] = alloca i1
-// WIN32: call x86_thiscallcc %struct.A* @"\01??0A@@QAE at XZ"
+// WIN32: call i8* @llvm.stacksave()
+// WIN32: %[[argmem:.*]] = alloca [[argmem_ty:<{ %struct.A, %struct.A }>]], inalloca
+// WIN32: %[[arg1:.*]] = getelementptr inbounds [[argmem_ty]]* %[[argmem]], i32 0, i32 1
+// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE at XZ"
// WIN32: invoke void @"\01?TakeRef@@YAXABUA@@@Z"
-// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE at XZ"(%struct.A* %[[arg1:.*]])
+//
+// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE at XZ"(%struct.A* %[[arg1]])
// WIN32: store i1 true, i1* %[[isactive]]
+//
+// WIN32: %[[arg0:.*]] = getelementptr inbounds [[argmem_ty]]* %[[argmem]], i32 0, i32 0
// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE at XZ"
// WIN32: invoke void @"\01?TakeRef@@YAXABUA@@@Z"
// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE at XZ"
// WIN32: store i1 false, i1* %[[isactive]]
-// WIN32: invoke i32 @"\01?TakesTwo@@YAHUA@@0 at Z"
+//
+// WIN32: invoke i32 @"\01?TakesTwo@@YAHUA@@0 at Z"([[argmem_ty]]* inalloca %[[argmem]])
+// WIN32: call void @llvm.stackrestore
// Destroy the two const ref temporaries.
// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE at XZ"
-// WIN32: call x86_thiscallcc void @"\01??1A@@QAE at XZ"
+// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE at XZ"
// WIN32: ret i32
//
// Conditionally destroy arg1.
@@ -60,20 +72,22 @@ int HasConditionalCleanup(bool cond) {
return (cond ? TakesTwo(A(), A()) : CouldThrow());
}
-// WIN32: define i32 @"\01?HasConditionalCleanup@@YAH_N at Z"(i1 zeroext %{{.*}}) {{.*}} {
+// WIN32-LABEL: define i32 @"\01?HasConditionalCleanup@@YAH_N at Z"(i1 zeroext %{{.*}}) {{.*}} {
// WIN32: store i1 false
// WIN32: br i1
-// No cleanups, so we call and then activate a cleanup if it succeeds.
-// WIN32: call x86_thiscallcc %struct.A* @"\01??0A@@QAE at XZ"(%struct.A* %[[arg1:.*]])
+// WIN32: call i8* @llvm.stacksave()
+// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE at XZ"(%struct.A* %{{.*}})
// WIN32: store i1 true
-// Now we have a cleanup for the first aggregate, so we invoke.
// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE at XZ"(%struct.A* %{{.*}})
-// Now we have no cleanups because TakeTwo will destruct both args.
-// WIN32: call i32 @"\01?TakesTwo@@YAHUA@@0 at Z"
-// Still no cleanups, so call.
+// WIN32: invoke i32 @"\01?TakesTwo@@YAHUA@@0 at Z"
+// WIN32: call void @llvm.stackrestore
+//
// WIN32: call i32 @"\01?CouldThrow@@YAHXZ"()
-// Somewhere in the landing pad for our single invoke, call the dtor.
-// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE at XZ"(%struct.A* %[[arg1]])
+//
+// Only one dtor in the invoke for arg1
+// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE at XZ"({{.*}})
+// WIN32-NOT: invoke x86_thiscallcc void @"\01??1A@@QAE at XZ"
+// WIN32: call void @llvm.stackrestore
// WIN32: }
// Now test both.
@@ -81,8 +95,7 @@ int HasConditionalDeactivatedCleanups(bo
return (cond ? TakesTwo((TakeRef(A()), A()), (TakeRef(A()), A())) : CouldThrow());
}
-// WIN32: define i32 @"\01?HasConditionalDeactivatedCleanups@@YAH_N at Z"{{.*}} {
-// WIN32: %[[arg1:.*]] = alloca %struct.A, align 4
+// WIN32-LABEL: define i32 @"\01?HasConditionalDeactivatedCleanups@@YAH_N at Z"{{.*}} {
// WIN32: alloca i1
// WIN32: %[[arg1_cond:.*]] = alloca i1
// Start all four cleanups as deactivated.
@@ -92,10 +105,10 @@ int HasConditionalDeactivatedCleanups(bo
// WIN32: store i1 false
// WIN32: br i1
// True condition.
-// WIN32: call x86_thiscallcc %struct.A* @"\01??0A@@QAE at XZ"
+// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE at XZ"
// WIN32: store i1 true
// WIN32: invoke void @"\01?TakeRef@@YAXABUA@@@Z"
-// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE at XZ"(%struct.A* %[[arg1]])
+// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE at XZ"
// WIN32: store i1 true, i1* %[[arg1_cond]]
// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE at XZ"
// WIN32: store i1 true
@@ -108,13 +121,13 @@ int HasConditionalDeactivatedCleanups(bo
// WIN32: invoke i32 @"\01?CouldThrow@@YAHXZ"()
// Two normal cleanups for TakeRef args.
// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE at XZ"
-// WIN32: call x86_thiscallcc void @"\01??1A@@QAE at XZ"
+// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE at XZ"
// WIN32: ret i32
//
// Somewhere in the landing pad soup, we conditionally destroy arg1.
// WIN32: %[[isactive:.*]] = load i1* %[[arg1_cond]]
// WIN32: br i1 %[[isactive]]
-// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE at XZ"(%struct.A* %[[arg1]])
+// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE at XZ"
// WIN32: }
namespace crash_on_partial_destroy {
Modified: cfe/trunk/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp?rev=200597&r1=200596&r2=200597&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp Fri Jan 31 18:04:45 2014
@@ -47,6 +47,14 @@ struct Big {
int a, b, c, d, e, f;
};
+// WIN32: declare void @"{{.*take_bools_and_chars.*}}"
+// WIN32: (<{ i8, [3 x i8], i8, [3 x i8], %struct.SmallWithDtor,
+// WIN32: i8, [3 x i8], i8, [3 x i8], i32, i8 }>* inalloca)
+void take_bools_and_chars(char a, char b, SmallWithDtor c, char d, bool e, int f, bool g);
+void call_bools_and_chars() {
+ take_bools_and_chars('A', 'B', SmallWithDtor(), 'D', true, 13, false);
+}
+
// Returning structs that fit into a register.
Small small_return() { return Small(); }
// LINUX-LABEL: define void @_Z12small_returnv(%struct.Small* noalias sret %agg.result)
@@ -103,11 +111,11 @@ void small_arg_with_ctor(SmallWithCtor s
// Test that dtors are invoked in the callee.
void small_arg_with_dtor(SmallWithDtor s) {}
-// WIN32: define void @"\01?small_arg_with_dtor@@YAXUSmallWithDtor@@@Z"(%struct.SmallWithDtor* byval align 4 %s) {{.*}} {
-// WIN32: call x86_thiscallcc void @"\01??1SmallWithDtor@@QAE at XZ"(%struct.SmallWithDtor* %s)
+// WIN32: define void @"\01?small_arg_with_dtor@@YAXUSmallWithDtor@@@Z"(<{ %struct.SmallWithDtor }>* inalloca) {{.*}} {
+// WIN32: call x86_thiscallcc void @"\01??1SmallWithDtor@@QAE at XZ"
// WIN32: }
-// WIN64: define void @"\01?small_arg_with_dtor@@YAXUSmallWithDtor@@@Z"(%struct.SmallWithDtor* byval %s) {{.*}} {
-// WIN64: call void @"\01??1SmallWithDtor@@QEAA at XZ"(%struct.SmallWithDtor* %s)
+// WIN64: define void @"\01?small_arg_with_dtor@@YAXUSmallWithDtor@@@Z"(%struct.SmallWithDtor* %s) {{.*}} {
+// WIN64: call void @"\01??1SmallWithDtor@@QEAA at XZ"
// WIN64: }
// Test that references aren't destroyed in the callee.
@@ -141,13 +149,13 @@ void eh_cleanup_arg_with_dtor() {
void small_arg_with_vftable(SmallWithVftable s) {}
// LINUX-LABEL: define void @_Z22small_arg_with_vftable16SmallWithVftable(%struct.SmallWithVftable* %s)
-// WIN32: define void @"\01?small_arg_with_vftable@@YAXUSmallWithVftable@@@Z"(%struct.SmallWithVftable* byval align 4 %s)
-// WIN64: define void @"\01?small_arg_with_vftable@@YAXUSmallWithVftable@@@Z"(%struct.SmallWithVftable* byval %s)
+// WIN32: define void @"\01?small_arg_with_vftable@@YAXUSmallWithVftable@@@Z"(<{ %struct.SmallWithVftable }>* inalloca)
+// WIN64: define void @"\01?small_arg_with_vftable@@YAXUSmallWithVftable@@@Z"(%struct.SmallWithVftable* %s)
void medium_arg_with_copy_ctor(MediumWithCopyCtor s) {}
// LINUX-LABEL: define void @_Z25medium_arg_with_copy_ctor18MediumWithCopyCtor(%struct.MediumWithCopyCtor* %s)
-// WIN32: define void @"\01?medium_arg_with_copy_ctor@@YAXUMediumWithCopyCtor@@@Z"(%struct.MediumWithCopyCtor* byval align 4 %s)
-// WIN64: define void @"\01?medium_arg_with_copy_ctor@@YAXUMediumWithCopyCtor@@@Z"(%struct.MediumWithCopyCtor* byval %s)
+// WIN32: define void @"\01?medium_arg_with_copy_ctor@@YAXUMediumWithCopyCtor@@@Z"(<{ %struct.MediumWithCopyCtor }>* inalloca)
+// WIN64: define void @"\01?medium_arg_with_copy_ctor@@YAXUMediumWithCopyCtor@@@Z"(%struct.MediumWithCopyCtor* %s)
void big_arg(Big s) {}
// LINUX-LABEL: define void @_Z7big_arg3Big(%struct.Big* byval align 4 %s)
@@ -215,8 +223,8 @@ struct X {
};
void g(X) {
}
-// WIN32: define void @"\01?g@@YAXUX@@@Z"(%struct.X* byval align 4) {{.*}} {
-// WIN32: call x86_thiscallcc void @"\01??1X@@QAE at XZ"(%struct.X* %0)
+// WIN32: define void @"\01?g@@YAXUX@@@Z"(<{ %struct.X }>* inalloca) {{.*}} {
+// WIN32: call x86_thiscallcc void @"\01??1X@@QAE at XZ"(%struct.X* {{.*}})
// WIN32: }
void f() {
g(X());
@@ -224,3 +232,34 @@ void f() {
// WIN32: define void @"\01?f@@YAXXZ"() {{.*}} {
// WIN32-NOT: call {{.*}} @"\01??1X@@QAE at XZ"
// WIN32: }
+
+
+namespace test2 {
+// We used to crash on this due to the mixture of POD byval and non-trivial
+// byval.
+
+struct NonTrivial {
+ NonTrivial();
+ NonTrivial(const NonTrivial &o);
+ ~NonTrivial();
+ int a;
+};
+struct POD { int b; };
+
+int foo(NonTrivial a, POD b);
+void bar() {
+ POD b;
+ b.b = 13;
+ int c = foo(NonTrivial(), b);
+}
+// WIN32-LABEL: define void @"\01?bar at test2@@YAXXZ"() {{.*}} {
+// WIN32: %[[argmem:[^ ]*]] = alloca [[argmem_ty:<{ %"struct.test2::NonTrivial", %"struct.test2::POD" }>]], inalloca
+// WIN32: getelementptr inbounds [[argmem_ty]]* %[[argmem]], i32 0, i32 1
+// WIN32: call void @llvm.memcpy
+// WIN32: getelementptr inbounds [[argmem_ty]]* %[[argmem]], i32 0, i32 0
+// WIN32: call x86_thiscallcc %"struct.test2::NonTrivial"* @"\01??0NonTrivial at test2@@QAE at XZ"
+// WIN32: call i32 @"\01?foo at test2@@YAHUNonTrivial at 1@UPOD at 1@@Z"([[argmem_ty]]* inalloca %argmem)
+// WIN32: ret void
+// WIN32: }
+
+}
Modified: cfe/trunk/test/CodeGenObjCXX/microsoft-abi-arc-param-order.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjCXX/microsoft-abi-arc-param-order.mm?rev=200597&r1=200596&r2=200597&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenObjCXX/microsoft-abi-arc-param-order.mm (original)
+++ cfe/trunk/test/CodeGenObjCXX/microsoft-abi-arc-param-order.mm Fri Jan 31 18:04:45 2014
@@ -10,11 +10,11 @@ struct A {
// Verify that we destruct things from left to right in the MS C++ ABI: a, b, c, d.
//
// CHECK-LABEL: define void @"\01?test_arc_order@@YAXUA@@PAAAPAUobjc_object@@01 at Z"
-// CHECK: ({{.*}} %[[a:.*]], {{.*}}, {{.*}} %[[c:.*]], {{.*}})
+// CHECK: (<{ %struct.A, i8*, %struct.A, i8* }>* inalloca)
void test_arc_order(A a, id __attribute__((ns_consumed)) b , A c, id __attribute__((ns_consumed)) d) {
- // CHECK: call x86_thiscallcc void @"\01??1A@@QAE at XZ"(%struct.A* %[[a]])
+ // CHECK: call x86_thiscallcc void @"\01??1A@@QAE at XZ"(%struct.A* %{{.*}})
// CHECK: call void @objc_storeStrong(i8** %{{.*}}, i8* null)
- // CHECK: call x86_thiscallcc void @"\01??1A@@QAE at XZ"(%struct.A* %[[c]])
+ // CHECK: call x86_thiscallcc void @"\01??1A@@QAE at XZ"(%struct.A* %{{.*}})
// CHECK: call void @objc_storeStrong(i8** %{{.*}}, i8* null)
// CHECK: ret void
}
More information about the cfe-commits
mailing list