Index: include/llvm/CodeGen/CallingConvLower.h =================================================================== --- include/llvm/CodeGen/CallingConvLower.h +++ include/llvm/CodeGen/CallingConvLower.h @@ -260,6 +260,10 @@ Locs.push_back(V); } + CCValAssign lastLoc() { + return Locs.back(); + } + LLVMContext &getContext() const { return Context; } MachineFunction &getMachineFunction() const { return MF; } CallingConv::ID getCallingConv() const { return CallingConv; } Index: include/llvm/Target/TargetCallingConv.h =================================================================== --- include/llvm/Target/TargetCallingConv.h +++ include/llvm/Target/TargetCallingConv.h @@ -48,6 +48,7 @@ unsigned IsCopyElisionCandidate : 1; ///< Argument copy elision candidate unsigned ByValSize; ///< Byval struct size + EVT OrigVt; ///< Original value type before split public: ArgFlagsTy() @@ -57,7 +58,8 @@ IsSecArgPass(0), ByValAlign(0), OrigAlign(0), IsInConsecutiveRegsLast(0), IsInConsecutiveRegs(0), IsCopyElisionCandidate(0), ByValSize(0) { - static_assert(sizeof(*this) == 2 * sizeof(unsigned), "flags are too big"); + static_assert(sizeof(*this) == 2 * sizeof(unsigned) + sizeof(EVT), + "flags are too big"); } bool isZExt() const { return IsZExt; } @@ -128,6 +130,9 @@ unsigned getByValSize() const { return ByValSize; } void setByValSize(unsigned S) { ByValSize = S; } + + EVT getOrigVt() const { return OrigVt; } + void setOrigVt(EVT Vt) { OrigVt = Vt; } }; /// InputArg - This struct carries flags and type information about a Index: include/llvm/Target/TargetCallingConv.td =================================================================== --- include/llvm/Target/TargetCallingConv.td +++ include/llvm/Target/TargetCallingConv.td @@ -32,6 +32,12 @@ list VTs = vts; } +/// CCIfSplitFrom - If the current argument is split from one of the specified +/// types, apply Action A. +class CCIfSplitFrom vts, CCAction A> : CCPredicateAction { + list VTs = vts; +} + /// CCIf - If the predicate matches, apply A. class CCIf : CCPredicateAction { string Predicate = predicate; @@ -150,6 +156,12 @@ ValueType DestTy = destTy; } +/// CCPassIndirectBySamePointer - Same as CCPassIndirect except pass by the +/// same pointer if the arguments have been split by legalizer. +class CCPassIndirectBySamePointer : CCAction { + ValueType DestTy = destTy; +} + /// CCDelegateTo - This action invokes the specified sub-calling-convention. It /// is successful if the specified CC matches. class CCDelegateTo : CCAction { Index: lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -8261,6 +8261,7 @@ MyFlags.Flags.setSplitEnd(); } + MyFlags.Flags.setOrigVt(VT); CLI.Outs.push_back(MyFlags); CLI.OutVals.push_back(Parts[j]); } @@ -8717,6 +8718,7 @@ if (i == NumRegs - 1) MyFlags.Flags.setSplitEnd(); } + MyFlags.Flags.setOrigVt(VT); Ins.push_back(MyFlags); } if (NeedsRegBlock && Value == NumValues - 1) Index: lib/Target/SystemZ/SystemZCallingConv.h =================================================================== --- lib/Target/SystemZ/SystemZCallingConv.h +++ lib/Target/SystemZ/SystemZCallingConv.h @@ -80,51 +80,6 @@ bool IsShortVector(unsigned ValNo) { return ArgIsShortVector[ValNo]; } }; -// Handle i128 argument types. These need to be passed by implicit -// reference. This could be as simple as the following .td line: -// CCIfType<[i128], CCPassIndirect>, -// except that i128 is not a legal type, and therefore gets split by -// common code into a pair of i64 arguments. -inline bool CC_SystemZ_I128Indirect(unsigned &ValNo, MVT &ValVT, - MVT &LocVT, - CCValAssign::LocInfo &LocInfo, - ISD::ArgFlagsTy &ArgFlags, - CCState &State) { - SmallVectorImpl &PendingMembers = State.getPendingLocs(); - - // ArgFlags.isSplit() is true on the first part of a i128 argument; - // PendingMembers.empty() is false on all subsequent parts. - if (!ArgFlags.isSplit() && PendingMembers.empty()) - return false; - - // Push a pending Indirect value location for each part. - LocVT = MVT::i64; - LocInfo = CCValAssign::Indirect; - PendingMembers.push_back(CCValAssign::getPending(ValNo, ValVT, - LocVT, LocInfo)); - if (!ArgFlags.isSplitEnd()) - return true; - - // OK, we've collected all parts in the pending list. Allocate - // the location (register or stack slot) for the indirect pointer. - // (This duplicates the usual i64 calling convention rules.) - unsigned Reg = State.AllocateReg(SystemZ::ArgGPRs); - unsigned Offset = Reg ? 0 : State.AllocateStack(8, 8); - - // Use that same location for all the pending parts. - for (auto &It : PendingMembers) { - if (Reg) - It.convertToReg(Reg); - else - It.convertToMem(Offset); - State.addLoc(It); - } - - PendingMembers.clear(); - - return true; -} - } // end namespace llvm #endif Index: lib/Target/SystemZ/SystemZCallingConv.td =================================================================== --- lib/Target/SystemZ/SystemZCallingConv.td +++ lib/Target/SystemZ/SystemZCallingConv.td @@ -76,9 +76,8 @@ // Force long double values to the stack and pass i64 pointers to them. CCIfType<[f128], CCPassIndirect>, - // Same for i128 values. These are already split into two i64 here, - // so we have to use a custom handler. - CCIfType<[i64], CCCustom<"CC_SystemZ_I128Indirect">>, + // Same for i128 values. These are already split into two i64 here. + CCIfType<[i64], CCIfSplitFrom<[i128], CCPassIndirectBySamePointer>>, // The first 5 integer arguments are passed in R2-R6. Note that R6 // is call-saved. Index: test/CodeGen/SystemZ/args-11.ll =================================================================== --- /dev/null +++ test/CodeGen/SystemZ/args-11.ll @@ -0,0 +1,21 @@ +; Test incoming i128 arguments. +; +; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s + +@a = local_unnamed_addr global i128 1, align 16 +@b = common local_unnamed_addr global float 0.000000e+00, align 4 + +; Function Attrs: norecurse nounwind +define signext i32 @main() local_unnamed_addr #0 { +; CHECK-LABEL: main: +; CHECK: lgrl %r0, a+8 +; CHECK: stg %r0, 168(%r15) +; CHECK: lgrl %r0, a +; CHECK: stg %r0, 160(%r15) +; CHECK: la %r2, 160(%r15) +; CHECK: brasl %r14, __floatuntisf@PLT + %1 = load i128, i128* @a, align 16 + %2 = uitofp i128 %1 to float + store float %2, float* @b, align 4 + ret i32 0 +} Index: utils/TableGen/CallingConvEmitter.cpp =================================================================== --- utils/TableGen/CallingConvEmitter.cpp +++ utils/TableGen/CallingConvEmitter.cpp @@ -92,7 +92,13 @@ if (i != 0) O << " ||\n " << IndentStr; O << "LocVT == " << getEnumName(getValueType(VT)); } - + } else if (Action->isSubClassOf("CCIfSplitFrom")) { + ListInit *VTs = Action->getValueAsListInit("VTs"); + for (unsigned i = 0, e = VTs->size(); i != e; ++i) { + Record *VT = VTs->getElementAsRecord(i); + if (i != 0) O << " ||\n " << IndentStr; + O << "ArgFlags.getOrigVt() == " << getEnumName(getValueType(VT)); + } } else if (Action->isSubClassOf("CCIf")) { O << Action->getValueAsString("Predicate"); } else { @@ -251,6 +257,14 @@ Record *DestTy = Action->getValueAsDef("DestTy"); O << IndentStr << "LocVT = " << getEnumName(getValueType(DestTy)) <<";\n"; O << IndentStr << "LocInfo = CCValAssign::BCvt;\n"; + } else if (Action->isSubClassOf("CCPassIndirectBySamePointer")) { + Record *DestTy = Action->getValueAsDef("DestTy"); + O << IndentStr << "LocVT = " << getEnumName(getValueType(DestTy)) <<";\n"; + O << IndentStr << "LocInfo = CCValAssign::Indirect;\n"; + O << IndentStr << "if (!ArgFlags.isSplit()) {\n" + << IndentStr << IndentStr << "State.addLoc(State.lastLoc());\n" + << IndentStr << IndentStr << "return false;\n" + << IndentStr << "}\n"; } else if (Action->isSubClassOf("CCPassIndirect")) { Record *DestTy = Action->getValueAsDef("DestTy"); O << IndentStr << "LocVT = " << getEnumName(getValueType(DestTy)) <<";\n";