diff options
-rw-r--r-- | lib/Target/SystemZ/SystemZISelLowering.cpp | 147 | ||||
-rw-r--r-- | lib/Target/SystemZ/SystemZISelLowering.h | 13 | ||||
-rw-r--r-- | lib/Target/SystemZ/SystemZInstrInfo.td | 15 | ||||
-rw-r--r-- | test/CodeGen/SystemZ/00-RetVoid.ll | 6 |
4 files changed, 180 insertions, 1 deletions
diff --git a/lib/Target/SystemZ/SystemZISelLowering.cpp b/lib/Target/SystemZ/SystemZISelLowering.cpp index 31572af..e22df99 100644 --- a/lib/Target/SystemZ/SystemZISelLowering.cpp +++ b/lib/Target/SystemZ/SystemZISelLowering.cpp @@ -48,10 +48,15 @@ SystemZTargetLowering::SystemZTargetLowering(SystemZTargetMachine &tm) : setStackPointerRegisterToSaveRestore(SystemZ::R15); setSchedulingPreference(SchedulingForLatency); + + setOperationAction(ISD::RET, MVT::Other, Custom); + } SDValue SystemZTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) { switch (Op.getOpcode()) { + case ISD::FORMAL_ARGUMENTS: return LowerFORMAL_ARGUMENTS(Op, DAG); + case ISD::RET: return LowerRET(Op, DAG); default: assert(0 && "unimplemented operand"); return SDValue(); @@ -64,8 +69,150 @@ SDValue SystemZTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) { #include "SystemZGenCallingConv.inc" +SDValue SystemZTargetLowering::LowerFORMAL_ARGUMENTS(SDValue Op, + SelectionDAG &DAG) { + unsigned CC = cast<ConstantSDNode>(Op.getOperand(1))->getZExtValue(); + switch (CC) { + default: + assert(0 && "Unsupported calling convention"); + case CallingConv::C: + case CallingConv::Fast: + return LowerCCCArguments(Op, DAG); + } +} + +/// LowerCCCArguments - transform physical registers into virtual registers and +/// generate load operations for arguments places on the stack. +// FIXME: struct return stuff +// FIXME: varargs +SDValue SystemZTargetLowering::LowerCCCArguments(SDValue Op, + SelectionDAG &DAG) { + MachineFunction &MF = DAG.getMachineFunction(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + MachineRegisterInfo &RegInfo = MF.getRegInfo(); + SDValue Root = Op.getOperand(0); + bool isVarArg = cast<ConstantSDNode>(Op.getOperand(2))->getZExtValue() != 0; + unsigned CC = MF.getFunction()->getCallingConv(); + DebugLoc dl = Op.getDebugLoc(); + + // Assign locations to all of the incoming arguments. + SmallVector<CCValAssign, 16> ArgLocs; + CCState CCInfo(CC, isVarArg, getTargetMachine(), ArgLocs); + CCInfo.AnalyzeFormalArguments(Op.getNode(), CC_SystemZ); + + assert(!isVarArg && "Varargs not supported yet"); + + SmallVector<SDValue, 16> ArgValues; + for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { + CCValAssign &VA = ArgLocs[i]; + if (VA.isRegLoc()) { + // Arguments passed in registers + MVT RegVT = VA.getLocVT(); + switch (RegVT.getSimpleVT()) { + default: + cerr << "LowerFORMAL_ARGUMENTS Unhandled argument type: " + << RegVT.getSimpleVT() + << "\n"; + abort(); + case MVT::i64: + unsigned VReg = + RegInfo.createVirtualRegister(SystemZ::GR64RegisterClass); + RegInfo.addLiveIn(VA.getLocReg(), VReg); + SDValue ArgValue = DAG.getCopyFromReg(Root, dl, VReg, RegVT); + + // If this is an 8/16/32-bit value, it is really passed promoted to 64 + // bits. Insert an assert[sz]ext to capture this, then truncate to the + // right size. + if (VA.getLocInfo() == CCValAssign::SExt) + ArgValue = DAG.getNode(ISD::AssertSext, dl, RegVT, ArgValue, + DAG.getValueType(VA.getValVT())); + else if (VA.getLocInfo() == CCValAssign::ZExt) + ArgValue = DAG.getNode(ISD::AssertZext, dl, RegVT, ArgValue, + DAG.getValueType(VA.getValVT())); + + if (VA.getLocInfo() != CCValAssign::Full) + ArgValue = DAG.getNode(ISD::TRUNCATE, dl, VA.getValVT(), ArgValue); + + ArgValues.push_back(ArgValue); + } + } else { + // Sanity check + assert(VA.isMemLoc()); + // Load the argument to a virtual register + unsigned ObjSize = VA.getLocVT().getSizeInBits()/8; + if (ObjSize > 8) { + cerr << "LowerFORMAL_ARGUMENTS Unhandled argument type: " + << VA.getLocVT().getSimpleVT() + << "\n"; + } + // Create the frame index object for this incoming parameter... + int FI = MFI->CreateFixedObject(ObjSize, VA.getLocMemOffset()); + + // Create the SelectionDAG nodes corresponding to a load + //from this parameter + SDValue FIN = DAG.getFrameIndex(FI, MVT::i64); + ArgValues.push_back(DAG.getLoad(VA.getLocVT(), dl, Root, FIN, + PseudoSourceValue::getFixedStack(FI), 0)); + } + } + + ArgValues.push_back(Root); + + // Return the new list of results. + return DAG.getNode(ISD::MERGE_VALUES, dl, Op.getNode()->getVTList(), + &ArgValues[0], ArgValues.size()).getValue(Op.getResNo()); +} + +SDValue SystemZTargetLowering::LowerRET(SDValue Op, SelectionDAG &DAG) { + // CCValAssign - represent the assignment of the return value to a location + SmallVector<CCValAssign, 16> RVLocs; + unsigned CC = DAG.getMachineFunction().getFunction()->getCallingConv(); + bool isVarArg = DAG.getMachineFunction().getFunction()->isVarArg(); + DebugLoc dl = Op.getDebugLoc(); + + // CCState - Info about the registers and stack slot. + CCState CCInfo(CC, isVarArg, getTargetMachine(), RVLocs); + + // Analize return values of ISD::RET + CCInfo.AnalyzeReturn(Op.getNode(), RetCC_SystemZ); + + // If this is the first return lowered for this function, add the regs to the + // liveout set for the function. + if (DAG.getMachineFunction().getRegInfo().liveout_empty()) { + for (unsigned i = 0; i != RVLocs.size(); ++i) + if (RVLocs[i].isRegLoc()) + DAG.getMachineFunction().getRegInfo().addLiveOut(RVLocs[i].getLocReg()); + } + + // The chain is always operand #0 + SDValue Chain = Op.getOperand(0); + SDValue Flag; + + // Copy the result values into the output registers. + for (unsigned i = 0; i != RVLocs.size(); ++i) { + CCValAssign &VA = RVLocs[i]; + assert(VA.isRegLoc() && "Can only return in registers!"); + + // ISD::RET => ret chain, (regnum1,val1), ... + // So i*2+1 index only the regnums + Chain = DAG.getCopyToReg(Chain, dl, VA.getLocReg(), + Op.getOperand(i*2+1), Flag); + + // Guarantee that all emitted copies are stuck together, + // avoiding something bad. + Flag = Chain.getValue(1); + } + + if (Flag.getNode()) + return DAG.getNode(SystemZISD::RET_FLAG, dl, MVT::Other, Chain, Flag); + + // Return Void + return DAG.getNode(SystemZISD::RET_FLAG, dl, MVT::Other, Chain); +} + const char *SystemZTargetLowering::getTargetNodeName(unsigned Opcode) const { switch (Opcode) { + case SystemZISD::RET_FLAG: return "SystemZISD::RET_FLAG"; default: return NULL; } } diff --git a/lib/Target/SystemZ/SystemZISelLowering.h b/lib/Target/SystemZ/SystemZISelLowering.h index ca9918d..feb5cd8 100644 --- a/lib/Target/SystemZ/SystemZISelLowering.h +++ b/lib/Target/SystemZ/SystemZISelLowering.h @@ -22,7 +22,10 @@ namespace llvm { namespace SystemZISD { enum { - FIRST_NUMBER = ISD::BUILTIN_OP_END + FIRST_NUMBER = ISD::BUILTIN_OP_END, + + /// Return with a flag operand. Operand 0 is the chain operand. + RET_FLAG }; } @@ -40,6 +43,14 @@ namespace llvm { /// DAG node. virtual const char *getTargetNodeName(unsigned Opcode) const; + SDValue LowerFORMAL_ARGUMENTS(SDValue Op, SelectionDAG &DAG); + SDValue LowerRET(SDValue Op, SelectionDAG &DAG); + SDValue LowerCCCArguments(SDValue Op, SelectionDAG &DAG); + + SDNode* LowerCallResult(SDValue Chain, SDValue InFlag, + CallSDNode *TheCall, + unsigned CallingConv, SelectionDAG &DAG); + private: const SystemZSubtarget &Subtarget; const SystemZTargetMachine &TM; diff --git a/lib/Target/SystemZ/SystemZInstrInfo.td b/lib/Target/SystemZ/SystemZInstrInfo.td index c2f27a1..54e0969 100644 --- a/lib/Target/SystemZ/SystemZInstrInfo.td +++ b/lib/Target/SystemZ/SystemZInstrInfo.td @@ -13,5 +13,20 @@ include "SystemZInstrFormats.td" +//===----------------------------------------------------------------------===// +// SystemZ Specific Node Definitions. +//===----------------------------------------------------------------------===// +def SystemZretflag : SDNode<"SystemZISD::RET_FLAG", SDTNone, + [SDNPHasChain, SDNPOptInFlag]>; + let neverHasSideEffects = 1 in def NOP : Pseudo<(outs), (ins), "# no-op", []>; + +//===----------------------------------------------------------------------===// +// Control Flow Instructions... +// + +// FIXME: Provide proper encoding! +let isReturn = 1, isTerminator = 1 in { + def RET : Pseudo<(outs), (ins), "br\t%r14", [(SystemZretflag)]>; +} diff --git a/test/CodeGen/SystemZ/00-RetVoid.ll b/test/CodeGen/SystemZ/00-RetVoid.ll new file mode 100644 index 0000000..3b0bb5a --- /dev/null +++ b/test/CodeGen/SystemZ/00-RetVoid.ll @@ -0,0 +1,6 @@ +; RUN: llvm-as < %s | llc -march=systemz + +define void @foo() { +entry: + ret void +}
\ No newline at end of file |