diff options
-rw-r--r-- | clang/include/clang/CodeGen/CGFunctionInfo.h | 33 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGCall.cpp | 350 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGCall.h | 21 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGClass.cpp | 3 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGDecl.cpp | 46 | ||||
-rw-r--r-- | clang/lib/CodeGen/CodeGenFunction.cpp | 16 | ||||
-rw-r--r-- | clang/lib/CodeGen/CodeGenFunction.h | 13 | ||||
-rw-r--r-- | clang/lib/CodeGen/CodeGenTypes.h | 4 | ||||
-rw-r--r-- | clang/lib/CodeGen/MicrosoftCXXABI.cpp | 10 | ||||
-rw-r--r-- | clang/lib/CodeGen/TargetInfo.cpp | 121 | ||||
-rw-r--r-- | clang/test/CodeGenCXX/copy-constructor-elim.cpp | 9 | ||||
-rw-r--r-- | clang/test/CodeGenCXX/microsoft-abi-arg-order.cpp | 19 | ||||
-rw-r--r-- | clang/test/CodeGenCXX/microsoft-abi-byval-sret.cpp | 26 | ||||
-rw-r--r-- | clang/test/CodeGenCXX/microsoft-abi-byval-vararg.cpp | 27 | ||||
-rw-r--r-- | clang/test/CodeGenCXX/microsoft-abi-exceptions.cpp | 63 | ||||
-rw-r--r-- | clang/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp | 59 | ||||
-rw-r--r-- | clang/test/CodeGenObjCXX/microsoft-abi-arc-param-order.mm | 6 |
17 files changed, 698 insertions, 128 deletions
diff --git a/clang/include/clang/CodeGen/CGFunctionInfo.h b/clang/include/clang/CodeGen/CGFunctionInfo.h index 5fe8bea90a4..cb8c5a01182 100644 --- a/clang/include/clang/CodeGen/CGFunctionInfo.h +++ b/clang/include/clang/CodeGen/CGFunctionInfo.h @@ -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::FoldingSetNode { 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); diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index c7290937a6f..7bf9082007c 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -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::arrangeCXXConstructorDeclaration(const CXXConstructorDecl *D, 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(unsigned llvmCC, 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 CGFunctionInfo &FI) { 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 CGFunctionInfo &FI) { switch (argAI.getKind()) { case ABIArgInfo::Ignore: + case ABIArgInfo::InAlloca: break; case ABIArgInfo::Indirect: { @@ -978,6 +1006,10 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI) { } } + // 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::ConstructAttributeList(const CGFunctionInfo &FI, 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::ConstructAttributeList(const CGFunctionInfo &FI, // 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::ConstructAttributeList(const CGFunctionInfo &FI, 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(const CGFunctionInfo &FI, // 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(const CGFunctionInfo &FI, ++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(const CGFunctionInfo &FI, ++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(const CGFunctionInfo &FI, 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(const CGFunctionInfo &FI, 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(const CGFunctionInfo &FI, 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(const CGFunctionInfo &FI, 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(const CGFunctionInfo &FI, 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(const CGFunctionInfo &FI, 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(const CGFunctionInfo &FI, ++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 CGFunctionInfo &FI, 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(const CGFunctionInfo &FI, 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::EmitDelegateCallArg(CallArgList &args, 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(CodeGenFunction &CGF, CallArgList &args, 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(CallArgList &Args, // 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(CallArgList &Args, } } +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(CallArgList &args, const Expr *E, // 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()) { + 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); + 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); - - pushDestroy(EHCleanup, RV.getAggregateAddr(), type, destroyCXXObject, - /*useEHCleanupForArray*/ true); + 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(QualType Ty, RValue RV, } } +/// \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 CGFunctionInfo &CallInfo, 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 CGFunctionInfo &CallInfo, } 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 CGFunctionInfo &CallInfo, 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 CGFunctionInfo &CallInfo, 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 CGFunctionInfo &CallInfo, } } + 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 CGFunctionInfo &CallInfo, 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 diff --git a/clang/lib/CodeGen/CGCall.h b/clang/lib/CodeGen/CGCall.h index 532cb59c62e..c51f06fdcd2 100644 --- a/clang/lib/CodeGen/CGCall.h +++ b/clang/lib/CodeGen/CGCall.h @@ -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 diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp index 273fed52d5c..4c48afe0752 100644 --- a/clang/lib/CodeGen/CGClass.cpp +++ b/clang/lib/CodeGen/CGClass.cpp @@ -1714,9 +1714,8 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D, // 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); } diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index e87be5f4148..cb48e84aacb 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -944,7 +944,7 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) { // 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(CleanupKind cleanupKind, llvm::Value *addr, 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 VarDecl &D, llvm::Value *Arg, } 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 VarDecl &D, llvm::Value *Arg, 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 VarDecl &D, llvm::Value *Arg, 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; diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index 572f5babd0a..7d451e8f6d0 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -276,6 +276,14 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) { 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(GlobalDecl GD, // 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"); diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 9f418ef434e..322f480c834 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -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. /// diff --git a/clang/lib/CodeGen/CodeGenTypes.h b/clang/lib/CodeGen/CodeGenTypes.h index d74f589a749..59e308995d0 100644 --- a/clang/lib/CodeGen/CodeGenTypes.h +++ b/clang/lib/CodeGen/CodeGenTypes.h @@ -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); diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp index 875591d0df9..3433c8ca30c 100644 --- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp @@ -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; } diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp index bf968f34815..53747e3fcd1 100644 --- a/clang/lib/CodeGen/TargetInfo.cpp +++ b/clang/lib/CodeGen/TargetInfo.cpp @@ -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::getIndirectResult(QualType Ty, bool ByVal, 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(QualType Ty, CCState &State, 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(CGFunctionInfo &FI) const { 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(llvm::Value *VAListAddr, QualType Ty, 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(llvm::Value *VAListAddr, QualType Ty, 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); diff --git a/clang/test/CodeGenCXX/copy-constructor-elim.cpp b/clang/test/CodeGenCXX/copy-constructor-elim.cpp index ad3a87b9d5f..8e9bee97377 100644 --- a/clang/test/CodeGenCXX/copy-constructor-elim.cpp +++ b/clang/test/CodeGenCXX/copy-constructor-elim.cpp @@ -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@ABV0 +// MS-NOT: ?0S@@QAE@ABV0 extern "C" int printf(...); diff --git a/clang/test/CodeGenCXX/microsoft-abi-arg-order.cpp b/clang/test/CodeGenCXX/microsoft-abi-arg-order.cpp index 4415c2e84a7..dff52ae9038 100644 --- a/clang/test/CodeGenCXX/microsoft-abi-arg-order.cpp +++ b/clang/test/CodeGenCXX/microsoft-abi-arg-order.cpp @@ -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@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@XZ"(%struct.A* %[[a]]) // CHECK: call x86_thiscallcc void @"\01??1A@@QAE@XZ"(%struct.A* %[[b]]) // CHECK: call x86_thiscallcc void @"\01??1A@@QAE@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@H@Z"(%struct.A* %[[arg3:.*]], i32 3) -// CHECK: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@H@Z"(%struct.A* %[[arg2:.*]], i32 2) -// CHECK: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@H@Z"(%struct.A* %[[arg1:.*]], i32 1) -// CHECK: call void @"\01?foo@@YAXUA@@00@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@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@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@H@Z"(%struct.A* %[[arg1]], i32 1) +// CHECK: invoke void @"\01?foo@@YAXUA@@00@Z"([[argmem_ty]]* inalloca %[[argmem]]) +// CHECK: call void @llvm.stackrestore // CHECK: ret void // // lpad2: diff --git a/clang/test/CodeGenCXX/microsoft-abi-byval-sret.cpp b/clang/test/CodeGenCXX/microsoft-abi-byval-sret.cpp new file mode 100644 index 00000000000..00d36b7d492 --- /dev/null +++ b/clang/test/CodeGenCXX/microsoft-abi-byval-sret.cpp @@ -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@A@@QAE?AU1@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@A@@QAE?AU1@U1@@Z" +// CHECK: (%struct.A* %{{[^,]*}}, <{ %struct.A*, %struct.A }>* inalloca %{{[^,]*}}) diff --git a/clang/test/CodeGenCXX/microsoft-abi-byval-vararg.cpp b/clang/test/CodeGenCXX/microsoft-abi-byval-vararg.cpp new file mode 100644 index 00000000000..33619216e88 --- /dev/null +++ b/clang/test/CodeGenCXX/microsoft-abi-byval-vararg.cpp @@ -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]]) diff --git a/clang/test/CodeGenCXX/microsoft-abi-exceptions.cpp b/clang/test/CodeGenCXX/microsoft-abi-exceptions.cpp index 6731c0effb0..ecce71d6c5c 100644 --- a/clang/test/CodeGenCXX/microsoft-abi-exceptions.cpp +++ b/clang/test/CodeGenCXX/microsoft-abi-exceptions.cpp @@ -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@Z" +// If this call throws, we have to cleanup the stacksave. +// WIN32: invoke i32 @"\01?TakesTwo@@YAHUA@@0@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@XZ" +// WIN32-NOT: @"\01??1A@@QAE@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@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@XZ" // WIN32: invoke void @"\01?TakeRef@@YAXABUA@@@Z" -// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"(%struct.A* %[[arg1:.*]]) +// +// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@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@XZ" // WIN32: invoke void @"\01?TakeRef@@YAXABUA@@@Z" // WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ" // WIN32: store i1 false, i1* %[[isactive]] -// WIN32: invoke i32 @"\01?TakesTwo@@YAHUA@@0@Z" +// +// WIN32: invoke i32 @"\01?TakesTwo@@YAHUA@@0@Z"([[argmem_ty]]* inalloca %[[argmem]]) +// WIN32: call void @llvm.stackrestore // Destroy the two const ref temporaries. // WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ" -// WIN32: call x86_thiscallcc void @"\01??1A@@QAE@XZ" +// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@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@Z"(i1 zeroext %{{.*}}) {{.*}} { +// WIN32-LABEL: define i32 @"\01?HasConditionalCleanup@@YAH_N@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@XZ"(%struct.A* %[[arg1:.*]]) +// WIN32: call i8* @llvm.stacksave() +// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@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@XZ"(%struct.A* %{{.*}}) -// Now we have no cleanups because TakeTwo will destruct both args. -// WIN32: call i32 @"\01?TakesTwo@@YAHUA@@0@Z" -// Still no cleanups, so call. +// WIN32: invoke i32 @"\01?TakesTwo@@YAHUA@@0@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@XZ"(%struct.A* %[[arg1]]) +// +// Only one dtor in the invoke for arg1 +// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ"({{.*}}) +// WIN32-NOT: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ" +// WIN32: call void @llvm.stackrestore // WIN32: } // Now test both. @@ -81,8 +95,7 @@ int HasConditionalDeactivatedCleanups(bool cond) { return (cond ? TakesTwo((TakeRef(A()), A()), (TakeRef(A()), A())) : CouldThrow()); } -// WIN32: define i32 @"\01?HasConditionalDeactivatedCleanups@@YAH_N@Z"{{.*}} { -// WIN32: %[[arg1:.*]] = alloca %struct.A, align 4 +// WIN32-LABEL: define i32 @"\01?HasConditionalDeactivatedCleanups@@YAH_N@Z"{{.*}} { // WIN32: alloca i1 // WIN32: %[[arg1_cond:.*]] = alloca i1 // Start all four cleanups as deactivated. @@ -92,10 +105,10 @@ int HasConditionalDeactivatedCleanups(bool cond) { // WIN32: store i1 false // WIN32: br i1 // True condition. -// WIN32: call x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ" +// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ" // WIN32: store i1 true // WIN32: invoke void @"\01?TakeRef@@YAXABUA@@@Z" -// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"(%struct.A* %[[arg1]]) +// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ" // WIN32: store i1 true, i1* %[[arg1_cond]] // WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ" // WIN32: store i1 true @@ -108,13 +121,13 @@ int HasConditionalDeactivatedCleanups(bool cond) { // WIN32: invoke i32 @"\01?CouldThrow@@YAHXZ"() // Two normal cleanups for TakeRef args. // WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ" -// WIN32: call x86_thiscallcc void @"\01??1A@@QAE@XZ" +// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@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@XZ"(%struct.A* %[[arg1]]) +// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ" // WIN32: } namespace crash_on_partial_destroy { diff --git a/clang/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp b/clang/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp index bff5647fdd5..98001370d1f 100644 --- a/clang/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp +++ b/clang/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp @@ -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@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@XZ" // WIN32: } -// WIN64: define void @"\01?small_arg_with_dtor@@YAXUSmallWithDtor@@@Z"(%struct.SmallWithDtor* byval %s) {{.*}} { -// WIN64: call void @"\01??1SmallWithDtor@@QEAA@XZ"(%struct.SmallWithDtor* %s) +// WIN64: define void @"\01?small_arg_with_dtor@@YAXUSmallWithDtor@@@Z"(%struct.SmallWithDtor* %s) {{.*}} { +// WIN64: call void @"\01??1SmallWithDtor@@QEAA@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@XZ"(%struct.X* %0) +// WIN32: define void @"\01?g@@YAXUX@@@Z"(<{ %struct.X }>* inalloca) {{.*}} { +// WIN32: call x86_thiscallcc void @"\01??1X@@QAE@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@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@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@test2@@QAE@XZ" +// WIN32: call i32 @"\01?foo@test2@@YAHUNonTrivial@1@UPOD@1@@Z"([[argmem_ty]]* inalloca %argmem) +// WIN32: ret void +// WIN32: } + +} diff --git a/clang/test/CodeGenObjCXX/microsoft-abi-arc-param-order.mm b/clang/test/CodeGenObjCXX/microsoft-abi-arc-param-order.mm index 3e01f03e26d..0b01b27fa79 100644 --- a/clang/test/CodeGenObjCXX/microsoft-abi-arc-param-order.mm +++ b/clang/test/CodeGenObjCXX/microsoft-abi-arc-param-order.mm @@ -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@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@XZ"(%struct.A* %[[a]]) + // CHECK: call x86_thiscallcc void @"\01??1A@@QAE@XZ"(%struct.A* %{{.*}}) // CHECK: call void @objc_storeStrong(i8** %{{.*}}, i8* null) - // CHECK: call x86_thiscallcc void @"\01??1A@@QAE@XZ"(%struct.A* %[[c]]) + // CHECK: call x86_thiscallcc void @"\01??1A@@QAE@XZ"(%struct.A* %{{.*}}) // CHECK: call void @objc_storeStrong(i8** %{{.*}}, i8* null) // CHECK: ret void } |