Some preliminary call lowering

llvm-svn: 75941
This commit is contained in:
Anton Korobeynikov 2009-07-16 13:50:21 +00:00
parent f4257ba74e
commit 4fcadd1a7d
9 changed files with 331 additions and 11 deletions

View File

@ -185,6 +185,20 @@ void SystemZAsmPrinter::printOperand(const MachineInstr *MI, int OpNum,
case MachineOperand::MO_MachineBasicBlock:
printBasicBlockLabel(MO.getMBB());
return;
case MachineOperand::MO_GlobalAddress: {
std::string Name = Mang->getValueName(MO.getGlobal());
assert(MO.getOffset() == 0 && "No offsets allowed!");
O << Name;
return;
}
case MachineOperand::MO_ExternalSymbol: {
std::string Name(TAI->getGlobalPrefix());
Name += MO.getSymbolName();
O << Name;
return;
}
default:
assert(0 && "Not implemented yet!");
}

View File

@ -61,6 +61,7 @@ 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);
case ISD::CALL: return LowerCALL(Op, DAG);
default:
assert(0 && "unimplemented operand");
return SDValue();
@ -85,6 +86,18 @@ SDValue SystemZTargetLowering::LowerFORMAL_ARGUMENTS(SDValue Op,
}
}
SDValue SystemZTargetLowering::LowerCALL(SDValue Op, SelectionDAG &DAG) {
CallSDNode *TheCall = cast<CallSDNode>(Op.getNode());
unsigned CallingConv = TheCall->getCallingConv();
switch (CallingConv) {
default:
assert(0 && "Unsupported calling convention");
case CallingConv::Fast:
case CallingConv::C:
return LowerCCCCallTo(Op, DAG, CallingConv);
}
}
/// LowerCCCArguments - transform physical registers into virtual registers and
/// generate load operations for arguments places on the stack.
// FIXME: struct return stuff
@ -167,6 +180,167 @@ SDValue SystemZTargetLowering::LowerCCCArguments(SDValue Op,
&ArgValues[0], ArgValues.size()).getValue(Op.getResNo());
}
/// LowerCCCCallTo - functions arguments are copied from virtual regs to
/// (physical regs)/(stack frame), CALLSEQ_START and CALLSEQ_END are emitted.
/// TODO: sret.
SDValue SystemZTargetLowering::LowerCCCCallTo(SDValue Op, SelectionDAG &DAG,
unsigned CC) {
CallSDNode *TheCall = cast<CallSDNode>(Op.getNode());
SDValue Chain = TheCall->getChain();
SDValue Callee = TheCall->getCallee();
bool isVarArg = TheCall->isVarArg();
DebugLoc dl = Op.getDebugLoc();
// Analyze operands of the call, assigning locations to each operand.
SmallVector<CCValAssign, 16> ArgLocs;
CCState CCInfo(CC, isVarArg, getTargetMachine(), ArgLocs);
CCInfo.AnalyzeCallOperands(TheCall, CC_SystemZ);
// Get a count of how many bytes are to be pushed on the stack.
unsigned NumBytes = CCInfo.getNextStackOffset();
Chain = DAG.getCALLSEQ_START(Chain ,DAG.getConstant(NumBytes,
getPointerTy(), true));
SmallVector<std::pair<unsigned, SDValue>, 4> RegsToPass;
SmallVector<SDValue, 12> MemOpChains;
SDValue StackPtr;
// Walk the register/memloc assignments, inserting copies/loads.
for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
CCValAssign &VA = ArgLocs[i];
// Arguments start after the 5 first operands of ISD::CALL
SDValue Arg = TheCall->getArg(i);
// Promote the value if needed.
switch (VA.getLocInfo()) {
default: assert(0 && "Unknown loc info!");
case CCValAssign::Full: break;
case CCValAssign::SExt:
Arg = DAG.getNode(ISD::SIGN_EXTEND, dl, VA.getLocVT(), Arg);
break;
case CCValAssign::ZExt:
Arg = DAG.getNode(ISD::ZERO_EXTEND, dl, VA.getLocVT(), Arg);
break;
case CCValAssign::AExt:
Arg = DAG.getNode(ISD::ANY_EXTEND, dl, VA.getLocVT(), Arg);
break;
}
// Arguments that can be passed on register must be kept at RegsToPass
// vector
if (VA.isRegLoc()) {
RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg));
} else {
assert(VA.isMemLoc());
if (StackPtr.getNode() == 0)
StackPtr = DAG.getCopyFromReg(Chain, dl, SystemZ::R15D, getPointerTy());
SDValue PtrOff = DAG.getNode(ISD::ADD, dl, getPointerTy(),
StackPtr,
DAG.getIntPtrConstant(VA.getLocMemOffset()));
MemOpChains.push_back(DAG.getStore(Chain, dl, Arg, PtrOff,
PseudoSourceValue::getStack(),
VA.getLocMemOffset()));
}
}
// Transform all store nodes into one single node because all store nodes are
// independent of each other.
if (!MemOpChains.empty())
Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other,
&MemOpChains[0], MemOpChains.size());
// Build a sequence of copy-to-reg nodes chained together with token chain and
// flag operands which copy the outgoing args into registers. The InFlag in
// necessary since all emited instructions must be stuck together.
SDValue InFlag;
for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) {
Chain = DAG.getCopyToReg(Chain, dl, RegsToPass[i].first,
RegsToPass[i].second, InFlag);
InFlag = Chain.getValue(1);
}
// If the callee is a GlobalAddress node (quite common, every direct call is)
// turn it into a TargetGlobalAddress node so that legalize doesn't hack it.
// Likewise ExternalSymbol -> TargetExternalSymbol.
if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee))
Callee = DAG.getTargetGlobalAddress(G->getGlobal(), getPointerTy());
else if (ExternalSymbolSDNode *E = dyn_cast<ExternalSymbolSDNode>(Callee))
Callee = DAG.getTargetExternalSymbol(E->getSymbol(), getPointerTy());
// Returns a chain & a flag for retval copy to use.
SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Flag);
SmallVector<SDValue, 8> Ops;
Ops.push_back(Chain);
Ops.push_back(Callee);
// Add argument registers to the end of the list so that they are
// known live into the call.
for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i)
Ops.push_back(DAG.getRegister(RegsToPass[i].first,
RegsToPass[i].second.getValueType()));
if (InFlag.getNode())
Ops.push_back(InFlag);
Chain = DAG.getNode(SystemZISD::CALL, dl, NodeTys, &Ops[0], Ops.size());
InFlag = Chain.getValue(1);
// Create the CALLSEQ_END node.
Chain = DAG.getCALLSEQ_END(Chain,
DAG.getConstant(NumBytes, getPointerTy(), true),
DAG.getConstant(0, getPointerTy(), true),
InFlag);
InFlag = Chain.getValue(1);
// Handle result values, copying them out of physregs into vregs that we
// return.
return SDValue(LowerCallResult(Chain, InFlag, TheCall, CC, DAG),
Op.getResNo());
}
/// LowerCallResult - Lower the result values of an ISD::CALL into the
/// appropriate copies out of appropriate physical registers. This assumes that
/// Chain/InFlag are the input chain/flag to use, and that TheCall is the call
/// being lowered. Returns a SDNode with the same number of values as the
/// ISD::CALL.
SDNode*
SystemZTargetLowering::LowerCallResult(SDValue Chain, SDValue InFlag,
CallSDNode *TheCall,
unsigned CallingConv,
SelectionDAG &DAG) {
bool isVarArg = TheCall->isVarArg();
DebugLoc dl = TheCall->getDebugLoc();
// Assign locations to each value returned by this call.
SmallVector<CCValAssign, 16> RVLocs;
CCState CCInfo(CallingConv, isVarArg, getTargetMachine(), RVLocs);
CCInfo.AnalyzeCallResult(TheCall, RetCC_SystemZ);
SmallVector<SDValue, 8> ResultVals;
// Copy all of the result registers out of their specified physreg.
for (unsigned i = 0; i != RVLocs.size(); ++i) {
Chain = DAG.getCopyFromReg(Chain, dl, RVLocs[i].getLocReg(),
RVLocs[i].getValVT(), InFlag).getValue(1);
InFlag = Chain.getValue(2);
ResultVals.push_back(Chain.getValue(0));
}
ResultVals.push_back(Chain);
// Merge everything together with a MERGE_VALUES node.
return DAG.getNode(ISD::MERGE_VALUES, dl, TheCall->getVTList(),
&ResultVals[0], ResultVals.size()).getNode();
}
SDValue SystemZTargetLowering::LowerRET(SDValue Op, SelectionDAG &DAG) {
// CCValAssign - represent the assignment of the return value to a location
SmallVector<CCValAssign, 16> RVLocs;
@ -226,6 +400,7 @@ SDValue SystemZTargetLowering::LowerRET(SDValue Op, SelectionDAG &DAG) {
const char *SystemZTargetLowering::getTargetNodeName(unsigned Opcode) const {
switch (Opcode) {
case SystemZISD::RET_FLAG: return "SystemZISD::RET_FLAG";
case SystemZISD::CALL: return "SystemZISD::CALL";
default: return NULL;
}
}

View File

@ -25,7 +25,11 @@ namespace llvm {
FIRST_NUMBER = ISD::BUILTIN_OP_END,
/// Return with a flag operand. Operand 0 is the chain operand.
RET_FLAG
RET_FLAG,
/// CALL/TAILCALL - These operations represent an abstract call
/// instruction, which includes a bunch of information.
CALL
};
}
@ -45,7 +49,10 @@ namespace llvm {
SDValue LowerFORMAL_ARGUMENTS(SDValue Op, SelectionDAG &DAG);
SDValue LowerRET(SDValue Op, SelectionDAG &DAG);
SDValue LowerCALL(SDValue Op, SelectionDAG &DAG);
SDValue LowerCCCArguments(SDValue Op, SelectionDAG &DAG);
SDValue LowerCCCCallTo(SDValue Op, SelectionDAG &DAG, unsigned CC);
SDNode* LowerCallResult(SDValue Chain, SDValue InFlag,
CallSDNode *TheCall,

View File

@ -117,14 +117,21 @@ bool
SystemZInstrInfo::spillCalleeSavedRegisters(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI,
const std::vector<CalleeSavedInfo> &CSI) const {
return false;
if (CSI.empty())
return false;
MachineFunction &MF = *MBB.getParent();
SystemZMachineFunctionInfo *MFI = MF.getInfo<SystemZMachineFunctionInfo>();
MFI->setCalleeSavedFrameSize(CSI.size() * 8);
return true;
}
bool
SystemZInstrInfo::restoreCalleeSavedRegisters(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI,
const std::vector<CalleeSavedInfo> &CSI) const {
return false;
return true;
}
unsigned

View File

@ -13,14 +13,34 @@
include "SystemZInstrFormats.td"
//===----------------------------------------------------------------------===//
// Type Constraints.
//===----------------------------------------------------------------------===//
class SDTCisI8<int OpNum> : SDTCisVT<OpNum, i8>;
class SDTCisI16<int OpNum> : SDTCisVT<OpNum, i16>;
class SDTCisI32<int OpNum> : SDTCisVT<OpNum, i32>;
class SDTCisI64<int OpNum> : SDTCisVT<OpNum, i64>;
//===----------------------------------------------------------------------===//
// Type Profiles.
//===----------------------------------------------------------------------===//
def SDT_SystemZCall : SDTypeProfile<0, -1, [SDTCisVT<0, iPTR>]>;
def SDT_SystemZCallSeqStart : SDCallSeqStart<[SDTCisI64<0>]>;
def SDT_SystemZCallSeqEnd : SDCallSeqEnd<[SDTCisI64<0>, SDTCisI64<1>]>;
//===----------------------------------------------------------------------===//
// SystemZ Specific Node Definitions.
//===----------------------------------------------------------------------===//
def SystemZretflag : SDNode<"SystemZISD::RET_FLAG", SDTNone,
[SDNPHasChain, SDNPOptInFlag]>;
let neverHasSideEffects = 1 in
def NOP : Pseudo<(outs), (ins), "# no-op", []>;
def SystemZcall : SDNode<"SystemZISD::CALL", SDT_SystemZCall,
[SDNPHasChain, SDNPOutFlag, SDNPOptInFlag]>;
def SystemZcallseq_start :
SDNode<"ISD::CALLSEQ_START", SDT_SystemZCallSeqStart,
[SDNPHasChain, SDNPOutFlag]>;
def SystemZcallseq_end :
SDNode<"ISD::CALLSEQ_END", SDT_SystemZCallSeqEnd,
[SDNPHasChain, SDNPOptInFlag, SDNPOutFlag]>;
//===----------------------------------------------------------------------===//
// Instruction Pattern Stuff.
@ -172,6 +192,23 @@ def laaddr : Operand<i64>,
let MIOperandInfo = (ops ADDR64:$base, i64imm:$disp, ADDR64:$index);
}
//===----------------------------------------------------------------------===//
// Instruction list..
// ADJCALLSTACKDOWN/UP implicitly use/def SP because they may be expanded into
// a stack adjustment and the codegen must know that they may modify the stack
// pointer before prolog-epilog rewriting occurs.
// Pessimistically assume ADJCALLSTACKDOWN / ADJCALLSTACKUP will become
// sub / add which can clobber R15D.
let Defs = [R15D], Uses = [R15D] in {
def ADJCALLSTACKDOWN : Pseudo<(outs), (ins i64imm:$amt),
"#ADJCALLSTACKDOWN",
[(SystemZcallseq_start timm:$amt)]>;
def ADJCALLSTACKUP : Pseudo<(outs), (ins i64imm:$amt1, i64imm:$amt2),
"#ADJCALLSTACKUP",
[(SystemZcallseq_end timm:$amt1, timm:$amt2)]>;
}
//===----------------------------------------------------------------------===//
// Control Flow Instructions...
@ -182,6 +219,22 @@ let isReturn = 1, isTerminator = 1, Uses = [R14D] in {
def RET : Pseudo<(outs), (ins), "br\t%r14", [(SystemZretflag)]>;
}
//===----------------------------------------------------------------------===//
// Call Instructions...
//
let isCall = 1 in
// All calls clobber the non-callee saved registers. R15 is marked as
// a use to prevent stack-pointer assignments that appear immediately
// before calls from potentially appearing dead. Uses for argument
// registers are added manually.
let Defs = [R0D, R1D, R3D, R4D, R5D, R14D, R15D],
Uses = [R15D] in {
def CALLi : Pseudo<(outs), (ins i64imm:$dst, variable_ops),
"brasl\t%r14, $dst", [(SystemZcall imm:$dst)]>;
def CALLr : Pseudo<(outs), (ins ADDR64:$dst, variable_ops),
"brasl\t%r14, $dst", [(SystemZcall ADDR64:$dst)]>;
}
//===----------------------------------------------------------------------===//
// Miscellaneous Instructions.
@ -193,6 +246,8 @@ def LA64r : Pseudo<(outs GR64:$dst), (ins laaddr:$src),
"lay\t{$dst, $src}",
[(set GR64:$dst, laaddr:$src)]>;
let neverHasSideEffects = 1 in
def NOP : Pseudo<(outs), (ins), "# no-op", []>;
//===----------------------------------------------------------------------===//
// Move Instructions
@ -525,3 +580,9 @@ def : Pat<(sext_inreg GR64:$src, i32),
def : Pat<(extloadi64i8 rriaddr:$src), (MOVZX64rm8 rriaddr:$src)>;
def : Pat<(extloadi64i16 rriaddr:$src), (MOVZX64rm16 rriaddr:$src)>;
def : Pat<(extloadi64i32 rriaddr:$src), (MOVZX64rm32 rriaddr:$src)>;
// calls
def : Pat<(SystemZcall (i64 tglobaladdr:$dst)),
(CALLi tglobaladdr:$dst)>;
def : Pat<(SystemZcall (i64 texternalsym:$dst)),
(CALLi texternalsym:$dst)>;

View File

@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "SystemZ.h"
#include "SystemZMachineFunctionInfo.h"
#include "SystemZRegisterInfo.h"
#include "SystemZSubtarget.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
@ -26,7 +27,7 @@ using namespace llvm;
SystemZRegisterInfo::SystemZRegisterInfo(SystemZTargetMachine &tm,
const TargetInstrInfo &tii)
: SystemZGenRegisterInfo(SystemZ::NOP, SystemZ::NOP),
: SystemZGenRegisterInfo(SystemZ::ADJCALLSTACKUP, SystemZ::ADJCALLSTACKDOWN),
TM(tm), TII(tii) {
}
@ -34,7 +35,7 @@ const unsigned*
SystemZRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
static const unsigned CalleeSavedRegs[] = {
SystemZ::R6D, SystemZ::R7D, SystemZ::R8D, SystemZ::R9D,
SystemZ::R10D, SystemZ::R11D, SystemZ::R12D, SystemZ::R13D,
SystemZ::R10D, SystemZ::R11D, SystemZ::R12D, SystemZ::R13D, SystemZ::R14D,
SystemZ::F1, SystemZ::F3, SystemZ::F5, SystemZ::F7,
0
};
@ -49,6 +50,7 @@ SystemZRegisterInfo::getCalleeSavedRegClasses(const MachineFunction *MF) const {
&SystemZ::GR64RegClass, &SystemZ::GR64RegClass,
&SystemZ::GR64RegClass, &SystemZ::GR64RegClass,
&SystemZ::GR64RegClass, &SystemZ::GR64RegClass,
&SystemZ::GR64RegClass,
&SystemZ::FP64RegClass, &SystemZ::FP64RegClass,
&SystemZ::FP64RegClass, &SystemZ::FP64RegClass, 0
};
@ -73,18 +75,32 @@ bool SystemZRegisterInfo::hasFP(const MachineFunction &MF) const {
return NoFramePointerElim || MFI->hasVarSizedObjects();
}
bool SystemZRegisterInfo::hasReservedCallFrame(MachineFunction &MF) const {
return !MF.getFrameInfo()->hasVarSizedObjects();
}
void SystemZRegisterInfo::
eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
MachineBasicBlock::iterator I) const {
assert(0 && "Not implemented yet!");
if (!hasReservedCallFrame(MF)) {
assert(0 && "Not implemented yet!");
}
MBB.erase(I);
}
int SystemZRegisterInfo::getFrameIndexOffset(MachineFunction &MF, int FI) const {
const TargetFrameInfo &TFI = *MF.getTarget().getFrameInfo();
MachineFrameInfo *MFI = MF.getFrameInfo();
SystemZMachineFunctionInfo *SystemZMFI =
MF.getInfo<SystemZMachineFunctionInfo>();
int Offset = MFI->getObjectOffset(FI) + MFI->getOffsetAdjustment();
uint64_t StackSize = MFI->getStackSize();
// Fixed objects are really located in the "previous" frame.
if (FI < 0)
StackSize -= SystemZMFI->getCalleeSavedFrameSize();
Offset += StackSize - TFI.getOffsetOfLocalArea();
// Skip the register save area if we generated the stack frame.
@ -149,12 +165,17 @@ void SystemZRegisterInfo::emitPrologue(MachineFunction &MF) const {
MachineBasicBlock &MBB = MF.front(); // Prolog goes in entry BB
const TargetFrameInfo &TFI = *MF.getTarget().getFrameInfo();
MachineFrameInfo *MFI = MF.getFrameInfo();
SystemZMachineFunctionInfo *SystemZMFI =
MF.getInfo<SystemZMachineFunctionInfo>();
MachineBasicBlock::iterator MBBI = MBB.begin();
DebugLoc DL = (MBBI != MBB.end() ? MBBI->getDebugLoc() :
DebugLoc::getUnknownLoc());
// Get the number of bytes to allocate from the FrameInfo.
uint64_t StackSize = MFI->getStackSize();
// Note that area for callee-saved stuff is already allocated, thus we need to
// 'undo' the stack movement.
uint64_t StackSize =
MFI->getStackSize() - SystemZMFI->getCalleeSavedFrameSize();
// FIXME: Skip the callee-saved push instructions.
@ -184,6 +205,8 @@ void SystemZRegisterInfo::emitEpilogue(MachineFunction &MF,
const MachineFrameInfo *MFI = MF.getFrameInfo();
const TargetFrameInfo &TFI = *MF.getTarget().getFrameInfo();
MachineBasicBlock::iterator MBBI = prior(MBB.end());
SystemZMachineFunctionInfo *SystemZMFI =
MF.getInfo<SystemZMachineFunctionInfo>();
unsigned RetOpcode = MBBI->getOpcode();
DebugLoc DL = MBBI->getDebugLoc();
@ -194,7 +217,10 @@ void SystemZRegisterInfo::emitEpilogue(MachineFunction &MF,
}
// Get the number of bytes to allocate from the FrameInfo
uint64_t StackSize = MFI->getStackSize();
// Note that area for callee-saved stuff is already allocated, thus we need to
// 'undo' the stack movement.
uint64_t StackSize =
MFI->getStackSize() - SystemZMFI->getCalleeSavedFrameSize();
uint64_t NumBytes = StackSize - TFI.getOffsetOfLocalArea();
// Skip the callee-saved regs load instructions.

View File

@ -37,6 +37,7 @@ struct SystemZRegisterInfo : public SystemZGenRegisterInfo {
BitVector getReservedRegs(const MachineFunction &MF) const;
bool hasReservedCallFrame(MachineFunction &MF) const;
bool hasFP(const MachineFunction &MF) const;
int getFrameIndexOffset(MachineFunction &MF, int FI) const;

View File

@ -0,0 +1,17 @@
; RUN: llvm-as < %s | llc | grep 168 | count 2
; RUN: llvm-as < %s | llc | grep 160 | count 3
; RUN: llvm-as < %s | llc | grep 328 | count 1
target datalayout = "E-p:64:64:64-i1:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-f128:128:128"
target triple = "s390x-unknown-linux-gnu"
define i64 @foo(i64 %b, i64 %c, i64 %d, i64 %e, i64 %f, i64 %g) nounwind {
entry:
%a = alloca i64, align 8 ; <i64*> [#uses=3]
store i64 %g, i64* %a
call void @bar(i64* %a) nounwind
%tmp1 = load i64* %a ; <i64> [#uses=1]
ret i64 %tmp1
}
declare void @bar(i64*)

View File

@ -0,0 +1,12 @@
; RUN: llvm-as < %s | llc
target datalayout = "E-p:64:64:64-i1:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-f128:128:128"
target triple = "s390x-unknown-linux-gnu"
define void @foo() nounwind {
entry:
tail call void @bar() nounwind
ret void
}
declare void @bar()