From b4997aeab74934ffa6fc0409afc4d8704245e372 Mon Sep 17 00:00:00 2001 From: Kenneth Uildriks Date: Sat, 7 Nov 2009 02:11:54 +0000 Subject: [PATCH] Add code to check at SelectionDAGISel::LowerArguments time to see if return values can be lowered to registers. Coming soon, code to perform sret-demotion if return values cannot be lowered to registers git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@86324 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/CodeGen/CallingConvLower.h | 7 +++ include/llvm/Target/TargetLowering.h | 12 ++++ lib/CodeGen/SelectionDAG/CallingConvLower.cpp | 15 +++++ .../SelectionDAG/SelectionDAGBuild.cpp | 60 +++++++++++++++++++ lib/Target/X86/X86ISelLowering.cpp | 11 ++++ lib/Target/X86/X86ISelLowering.h | 6 ++ 6 files changed, 111 insertions(+) diff --git a/include/llvm/CodeGen/CallingConvLower.h b/include/llvm/CodeGen/CallingConvLower.h index 5e730fc12cc..45a2757d378 100644 --- a/include/llvm/CodeGen/CallingConvLower.h +++ b/include/llvm/CodeGen/CallingConvLower.h @@ -183,6 +183,13 @@ public: void AnalyzeReturn(const SmallVectorImpl &Outs, CCAssignFn Fn); + /// CheckReturn - Analyze the return values of a function, returning + /// true if the return can be performed without sret-demotion, and + /// false otherwise. + bool CheckReturn(const SmallVectorImpl &OutTys, + const SmallVectorImpl &ArgsFlags, + CCAssignFn Fn); + /// AnalyzeCallOperands - Analyze the outgoing arguments to a call, /// incorporating info about the passed values into this state. void AnalyzeCallOperands(const SmallVectorImpl &Outs, diff --git a/include/llvm/Target/TargetLowering.h b/include/llvm/Target/TargetLowering.h index 8bc39d0b2ce..1526a0de0c5 100644 --- a/include/llvm/Target/TargetLowering.h +++ b/include/llvm/Target/TargetLowering.h @@ -1167,6 +1167,18 @@ public: return SDValue(); // this is here to silence compiler errors } + /// CanLowerReturn - This hook should be implemented to check whether the + /// return values described by the Outs array can fit into the return + /// registers. If false is returned, an sret-demotion is performed. + /// + virtual bool CanLowerReturn(CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl &OutTys, + const SmallVectorImpl &ArgsFlags, + SelectionDAG &DAG) + { + // Return true by default to get preexisting behavior. + return true; + } /// LowerReturn - This hook must be implemented to lower outgoing /// return values, described by the Outs array, into the specified /// DAG. The implementation should return the resulting token chain diff --git a/lib/CodeGen/SelectionDAG/CallingConvLower.cpp b/lib/CodeGen/SelectionDAG/CallingConvLower.cpp index fbe40b67863..38839c44131 100644 --- a/lib/CodeGen/SelectionDAG/CallingConvLower.cpp +++ b/lib/CodeGen/SelectionDAG/CallingConvLower.cpp @@ -77,6 +77,21 @@ CCState::AnalyzeFormalArguments(const SmallVectorImpl &Ins, } } +/// CheckReturn - Analyze the return values of a function, returning true if +/// the return can be performed without sret-demotion, and false otherwise. +bool CCState::CheckReturn(const SmallVectorImpl &OutTys, + const SmallVectorImpl &ArgsFlags, + CCAssignFn Fn) { + // Determine which register each value should be copied into. + for (unsigned i = 0, e = OutTys.size(); i != e; ++i) { + EVT VT = OutTys[i]; + ISD::ArgFlagsTy ArgFlags = ArgsFlags[i]; + if (Fn(i, VT, VT, CCValAssign::Full, ArgFlags, *this)) + return false; + } + return true; +} + /// AnalyzeReturn - Analyze the returned values of a return, /// incorporating info about the result values into this state. void CCState::AnalyzeReturn(const SmallVectorImpl &Outs, diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGBuild.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGBuild.cpp index c0d2a4d39a3..1ff1cd30f24 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGBuild.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGBuild.cpp @@ -947,6 +947,58 @@ SDValue SelectionDAGLowering::getValue(const Value *V) { return RFV.getCopyFromRegs(DAG, getCurDebugLoc(), Chain, NULL); } +/// Get the EVTs and ArgFlags collections that represent the return type +/// of the given function. This does not require a DAG or a return value, and +/// is suitable for use before any DAGs for the function are constructed. +static void getReturnInfo(const Function* F, SmallVectorImpl &OutVTs, + SmallVectorImpl &OutFlags, + TargetLowering &TLI) { + const Type* ReturnType = F->getReturnType(); + + SmallVector ValueVTs; + ComputeValueVTs(TLI, ReturnType, ValueVTs); + unsigned NumValues = ValueVTs.size(); + if ( NumValues == 0 ) return; + + for (unsigned j = 0, f = NumValues; j != f; ++j) { + EVT VT = ValueVTs[j]; + ISD::NodeType ExtendKind = ISD::ANY_EXTEND; + + if (F->paramHasAttr(0, Attribute::SExt)) + ExtendKind = ISD::SIGN_EXTEND; + else if (F->paramHasAttr(0, Attribute::ZExt)) + ExtendKind = ISD::ZERO_EXTEND; + + // FIXME: C calling convention requires the return type to be promoted to + // at least 32-bit. But this is not necessary for non-C calling + // conventions. The frontend should mark functions whose return values + // require promoting with signext or zeroext attributes. + if (ExtendKind != ISD::ANY_EXTEND && VT.isInteger()) { + EVT MinVT = TLI.getRegisterType(F->getContext(), MVT::i32); + if (VT.bitsLT(MinVT)) + VT = MinVT; + } + + unsigned NumParts = TLI.getNumRegisters(F->getContext(), VT); + EVT PartVT = TLI.getRegisterType(F->getContext(), VT); + // 'inreg' on function refers to return value + ISD::ArgFlagsTy Flags = ISD::ArgFlagsTy(); + if (F->paramHasAttr(0, Attribute::InReg)) + Flags.setInReg(); + + // Propagate extension type if any + if (F->paramHasAttr(0, Attribute::SExt)) + Flags.setSExt(); + else if (F->paramHasAttr(0, Attribute::ZExt)) + Flags.setZExt(); + + for (unsigned i = 0; i < NumParts; ++i) + { + OutVTs.push_back(PartVT); + OutFlags.push_back(Flags); + } + } +} void SelectionDAGLowering::visitRet(ReturnInst &I) { SDValue Chain = getControlRoot(); @@ -5758,6 +5810,14 @@ void SelectionDAGISel::LowerArguments(BasicBlock *LLVMBB) { DebugLoc dl = SDL->getCurDebugLoc(); const TargetData *TD = TLI.getTargetData(); + // Check whether the function can return without sret-demotion. + SmallVector OutVTs; + SmallVector OutsFlags; + getReturnInfo(&F, OutVTs, OutsFlags, TLI); + // For now, assert and bail out if it can't. + assert(TLI.CanLowerReturn(F.getCallingConv(), F.isVarArg(), OutVTs, OutsFlags, + DAG) && "Cannot fit return value in registers!"); + // Set up the incoming argument description vector. SmallVector Ins; unsigned Idx = 1; diff --git a/lib/Target/X86/X86ISelLowering.cpp b/lib/Target/X86/X86ISelLowering.cpp index 86ec9f2f17a..3b11ef4e369 100644 --- a/lib/Target/X86/X86ISelLowering.cpp +++ b/lib/Target/X86/X86ISelLowering.cpp @@ -1087,6 +1087,17 @@ unsigned X86TargetLowering::getFunctionAlignment(const Function *F) const { #include "X86GenCallingConv.inc" +bool +X86TargetLowering::CanLowerReturn(CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl &OutTys, + const SmallVectorImpl &ArgsFlags, + SelectionDAG &DAG) { + SmallVector RVLocs; + CCState CCInfo(CallConv, isVarArg, getTargetMachine(), + RVLocs, *DAG.getContext()); + return CCInfo.CheckReturn(OutTys, ArgsFlags, RetCC_X86); +} + SDValue X86TargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv, bool isVarArg, diff --git a/lib/Target/X86/X86ISelLowering.h b/lib/Target/X86/X86ISelLowering.h index 7b59b81f81a..0755284a9e2 100644 --- a/lib/Target/X86/X86ISelLowering.h +++ b/lib/Target/X86/X86ISelLowering.h @@ -699,6 +699,12 @@ namespace llvm { const SmallVectorImpl &Outs, DebugLoc dl, SelectionDAG &DAG); + virtual bool + CanLowerReturn(CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl &OutTys, + const SmallVectorImpl &ArgsFlags, + SelectionDAG &DAG); + void ReplaceATOMIC_BINARY_64(SDNode *N, SmallVectorImpl &Results, SelectionDAG &DAG, unsigned NewOp);