#if 0 //===- SparcV8ISelPattern.cpp - A pattern matching isel for SparcV8 -------===// // // The LLVM Compiler Infrastructure // // This file was developed by the LLVM research group and is distributed under // the University of Illinois Open Source License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file defines a pattern matching instruction selector for SparcV8. // //===----------------------------------------------------------------------===// //Please note that this file is a work in progress, and not a high //priority for anyone. #include "SparcV8.h" #include "SparcV8RegisterInfo.h" #include "llvm/Constants.h" // FIXME: REMOVE #include "llvm/Function.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineConstantPool.h" // FIXME: REMOVE #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/SelectionDAG.h" #include "llvm/CodeGen/SelectionDAGISel.h" #include "llvm/CodeGen/SSARegMap.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetLowering.h" #include "llvm/Support/MathExtras.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/Debug.h" #include "llvm/Support/CommandLine.h" #include #include using namespace llvm; //===----------------------------------------------------------------------===// // V8TargetLowering - SparcV8 Implementation of the TargetLowering interface namespace { class V8TargetLowering : public TargetLowering { int VarArgsFrameIndex; // FrameIndex for start of varargs area. public: V8TargetLowering(TargetMachine &TM) : TargetLowering(TM) { // Set up the TargetLowering object. //I am having problems with shr n ubyte 1 setShiftAmountType(MVT::i32); setSetCCResultType(MVT::i32); setSetCCResultContents(ZeroOrOneSetCCResult); //FIXME: get these right addRegisterClass(MVT::i64, V8::GPRCRegisterClass); addRegisterClass(MVT::f64, V8::FPRCRegisterClass); addRegisterClass(MVT::f32, V8::FPRCRegisterClass); setOperationAction(ISD::BRCONDTWOWAY, MVT::Other, Expand); setOperationAction(ISD::BRTWOWAY_CC, MVT::Other, Expand); setOperationAction(ISD::EXTLOAD, MVT::i1, Promote); setOperationAction(ISD::EXTLOAD, MVT::f32, Promote); setOperationAction(ISD::ZEXTLOAD, MVT::i1, Expand); setOperationAction(ISD::SEXTLOAD, MVT::i1, Expand); setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand); setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i8, Expand); setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i16, Expand); setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i32, Expand); setOperationAction(ISD::UREM, MVT::i32, Expand); setOperationAction(ISD::SREM, MVT::i32, Expand); setOperationAction(ISD::CTPOP, MVT::i32, Expand); setOperationAction(ISD::CTTZ, MVT::i32, Expand); setOperationAction(ISD::CTLZ, MVT::i32, Expand); setOperationAction(ISD::MEMMOVE, MVT::Other, Expand); setOperationAction(ISD::MEMSET, MVT::Other, Expand); setOperationAction(ISD::MEMCPY, MVT::Other, Expand); // We don't support sin/cos/sqrt setOperationAction(ISD::FSIN , MVT::f64, Expand); setOperationAction(ISD::FCOS , MVT::f64, Expand); setOperationAction(ISD::FSQRT, MVT::f64, Expand); setOperationAction(ISD::FSIN , MVT::f32, Expand); setOperationAction(ISD::FCOS , MVT::f32, Expand); setOperationAction(ISD::FSQRT, MVT::f32, Expand); computeRegisterProperties(); addLegalFPImmediate(+0.0); //F31 addLegalFPImmediate(-0.0); //-F31 } /// LowerArguments - This hook must be implemented to indicate how we should /// lower the arguments for the specified function, into the specified DAG. virtual std::vector LowerArguments(Function &F, SelectionDAG &DAG); /// LowerCallTo - This hook lowers an abstract call to a function into an /// actual call. virtual std::pair LowerCallTo(SDOperand Chain, const Type *RetTy, bool isVarArg, unsigned CC, bool isTailCall, SDOperand Callee, ArgListTy &Args, SelectionDAG &DAG); }; } /// AddLiveIn - This helper function adds the specified physical register to the /// MachineFunction as a live in value. It also creates a corresponding virtual /// register for it. static unsigned AddLiveIn(MachineFunction &MF, unsigned PReg, TargetRegisterClass *RC) { assert(RC->contains(PReg) && "Not the correct regclass!"); unsigned VReg = MF.getSSARegMap()->createVirtualRegister(RC); MF.addLiveIn(PReg, VReg); return VReg; } std::vector V8TargetLowering::LowerArguments(Function &F, SelectionDAG &DAG) { static const unsigned IncomingArgRegs[] = { V8::I0, V8::I1, V8::I2, V8::I3, V8::I4, V8::I5 }; std::vector ArgValues; MachineFunction &MF = DAG.getMachineFunction(); MachineFrameInfo*MFI = MF.getFrameInfo(); MachineBasicBlock& BB = MF.front(); unsigned ArgNo = 0; unsigned ArgOffset = 92; for (Function::arg_iterator I = F.arg_begin(), E = F.arg_end(); I != E; ++I, ++ArgNo) { MVT::ValueType VT = getValueType(I->getType()); SDOperand argt; if (ArgNo < 6) { switch(VT) { default: std::cerr << "Unknown Type " << VT << "\n"; abort(); case MVT::f64: case MVT::i64: //FIXME: figure out the build pair thing assert(0 && "doubles and longs not supported yet"); case MVT::f32: argt = DAG.getCopyFromReg(AddLiveIn(MF, IncomingArgRegs[ArgNo], MVT::i32), VT, DAG.getRoot()); //copy out of Int reg argt = DAG.getNode(ISD::FP_TO_UINT, MVT::f32, argt); break; case MVT::i1: case MVT::i8: case MVT::i16: case MVT::i32: argt = DAG.getCopyFromReg(AddLiveIn(MF, IncomingArgRegs[ArgNo], getRegClassFor(MVT::i32)), VT, DAG.getRoot()); if (VT != MVT::i32) argt = DAG.getNode(ISD::TRUNCATE, VT, argt); break; } DAG.setRoot(argt.getValue(1)); } else { //stack passed switch(VT) { default: std::cerr << "Unknown Type " << VT << "\n"; abort(); case MVT::f64: case MVT::i64: //FIXME: figure out the build pair thing assert(0 && "doubles and longs not supported yet"); case MVT::f32: case MVT::i1: case MVT::i8: case MVT::i16: case MVT::i32: // Create the frame index object for this incoming parameter... int FI = MFI->CreateFixedObject(4, ArgOffset); argt = DAG.getLoad(VT, DAG.getEntryNode(), DAG.getFramIndex(FI, MVT::i32), DAG.getSrcValue(NULL)); ArgOffset += 4; break; } ArgValues.push_back(argt); } } //return the arguments return ArgValues; } std::pair V8TargetLowering::LowerCallTo(SDOperand Chain, const Type *RetTy, bool isVarArg, unsigned CallingConv, bool isTailCall, SDOperand Callee, ArgListTy &Args, SelectionDAG &DAG) { //FIXME return std::make_pair(Chain, Chain); } namespace { //===--------------------------------------------------------------------===// /// ISel - V8 specific code to select V8 machine instructions for /// SelectionDAG operations. //===--------------------------------------------------------------------===// class ISel : public SelectionDAGISel { /// V8Lowering - This object fully describes how to lower LLVM code to an /// V8-specific SelectionDAG. V8TargetLowering V8Lowering; SelectionDAG *ISelDAG; // Hack to support us having a dag->dag transform // for sdiv and udiv until it is put into the future // dag combiner. /// ExprMap - As shared expressions are codegen'd, we keep track of which /// vreg the value is produced in, so we only emit one copy of each compiled /// tree. static const unsigned notIn = (unsigned)(-1); std::map ExprMap; public: ISel(TargetMachine &TM) : SelectionDAGISel(V8Lowering), V8Lowering(TM) {} /// InstructionSelectBasicBlock - This callback is invoked by /// SelectionDAGISel when it has created a SelectionDAG for us to codegen. virtual void InstructionSelectBasicBlock(SelectionDAG &DAG) { DEBUG(BB->dump()); // Codegen the basic block. ISelDAG = &DAG; max_depth = DAG.getRoot().getNodeDepth(); Select(DAG.getRoot()); // Clear state used for selection. ExprMap.clear(); } virtual void EmitFunctionEntryCode(Function &Fn, MachineFunction &MF); unsigned SelectExpr(SDOperand N); void Select(SDOperand N); }; } void ISel::EmitFunctionEntryCode(Function &Fn, MachineFunction &MF) { // If this function has live-in values, emit the copies from pregs to vregs at // the top of the function, before anything else. MachineBasicBlock *BB = MF.begin(); if (MF.livein_begin() != MF.livein_end()) { SSARegMap *RegMap = MF.getSSARegMap(); for (MachineFunction::livein_iterator LI = MF.livein_begin(), E = MF.livein_end(); LI != E; ++LI) { const TargetRegisterClass *RC = RegMap->getRegClass(LI->second); if (RC == V8::GPRCRegisterClass) { BuildMI(BB, V8::ORrr, 2, LI->second).addReg(LI->first).addReg(V8::G0); } else if (RC == V8::FPRCRegisterClass) { BuildMI(BB, V8::FMOVSrr, 2, LI->second).addReg(LI->first); } else { assert(0 && "Unknown regclass!"); } } } } //These describe LDAx static const int IMM_LOW = -32768; static const int IMM_HIGH = 32767; static const int IMM_MULT = 65536; static long getUpper16(long l) { long y = l / IMM_MULT; if (l % IMM_MULT > IMM_HIGH) ++y; return y; } static long getLower16(long l) { long h = getUpper16(l); return l - h * IMM_MULT; } unsigned ISel::SelectExpr(SDOperand N) { unsigned Result; unsigned Tmp1, Tmp2 = 0, Tmp3; unsigned Opc = 0; unsigned opcode = N.getOpcode(); SDNode *Node = N.Val; MVT::ValueType DestType = N.getValueType(); unsigned &Reg = ExprMap[N]; if (Reg) return Reg; if (N.getOpcode() != ISD::CALL && N.getOpcode() != ISD::TAILCALL) Reg = Result = (N.getValueType() != MVT::Other) ? MakeReg(N.getValueType()) : notIn; else { // If this is a call instruction, make sure to prepare ALL of the result // values as well as the chain. if (Node->getNumValues() == 1) Reg = Result = notIn; // Void call, just a chain. else { Result = MakeReg(Node->getValueType(0)); ExprMap[N.getValue(0)] = Result; for (unsigned i = 1, e = N.Val->getNumValues()-1; i != e; ++i) ExprMap[N.getValue(i)] = MakeReg(Node->getValueType(i)); ExprMap[SDOperand(Node, Node->getNumValues()-1)] = notIn; } } switch (opcode) { default: Node->dump(); assert(0 && "Node not handled!\n"); case ISD::EXTLOAD: case ISD::ZEXTLOAD: case ISD::SEXTLOAD: case ISD::LOAD: { // Make sure we generate both values. if (Result != notIn) ExprMap[N.getValue(1)] = notIn; // Generate the token else Result = ExprMap[N.getValue(0)] = MakeReg(N.getValue(0).getValueType()); SDOperand Chain = N.getOperand(0); SDOperand Address = N.getOperand(1); Select(Chain); unsigned Adr = SelectExpr(Address); switch(cast(Node->getOperand(3))->getVT()) { case MVT::i32: Opc = V8::LD; case MVT::i16: Opc = opcode == ISD::ZEXTLOAD ? V8::LDUH : V8::LDSH; break; case MVT::i8: Opc = opcode == ISD::ZEXTLOAD ? V8::LDUB : V8::LDSB; break; case MVT::f64: Opc = V8::LDFSRrr; case MVT::f32: Opc = V8::LDDFrr; default: Node->dump(); assert(0 && "Bad type!"); break; } BuildMI(BB, Opc, 1, Result).addReg(Adr); return Result; } case ISD::TAILCALL: case ISD::CALL: { //FIXME: abort(); return Result; } case ISD::CopyFromReg: { // Make sure we generate both values. if (Result != notIn) ExprMap[N.getValue(1)] = notIn; // Generate the token else Result = ExprMap[N.getValue(0)] = MakeReg(N.getValue(0).getValueType()); SDOperand Chain = N.getOperand(0); Select(Chain); unsigned r = dyn_cast(Node)->getReg(); BuildMI(BB, V8::ORrr, 2, Result).addReg(r).addReg(V8::G0); return Result; } //Most of the plain arithmetic and logic share the same form, and the same //constant immediate test case ISD::XOR: case ISD::AND: case ISD::OR: case ISD::SHL: case ISD::SRL: case ISD::SRA: case ISD::ADD: case ISD::SUB: case ISD::SDIV: case ISD::UDIV: case ISD::SMUL: case ISD::UMUL: switch(opcode) { case ISD::XOR: Opc = V8::XORrr; break; case ISD::AND: Opc = V8::ANDrr; break; case ISD::OR: Opc = V8::ORrr; break; case ISD::SHL: Opc = V8::SLLrr; break; case ISD::SRL: Opc = V8::SRLrr; break; case ISD::SRA: Opc = V8::SRArr; break; case ISD::ADD: Opc = V8::ADDrr; break; case ISD::SUB: Opc = V8::SUBrr; break; case ISD::SDIV: Opc = V8::SDIVrr; break; case ISD::UDIV: Opc = V8::UDIVrr; break; case ISD::SMUL: Opc = V8::SMULrr; break; case ISD::UMUL: Opc = V8::UMULrr; break; } Tmp1 = SelectExpr(N.getOperand(0)); Tmp2 = SelectExpr(N.getOperand(1)); BuildMI(BB, Opc, 2, Result).addReg(Tmp1).addReg(Tmp2); return Result; } return 0; } void ISel::Select(SDOperand N) { unsigned Tmp1, Tmp2, Opc; unsigned opcode = N.getOpcode(); if (!ExprMap.insert(std::make_pair(N, notIn)).second) return; // Already selected. SDNode *Node = N.Val; switch (opcode) { default: Node->dump(); std::cerr << "\n"; assert(0 && "Node not handled yet!"); case ISD::BRCOND: { //FIXME abort(); return; } case ISD::BR: { MachineBasicBlock *Dest = cast(N.getOperand(1))->getBasicBlock(); Select(N.getOperand(0)); BuildMI(BB, V8::BA, 1).addMBB(Dest); return; } case ISD::ImplicitDef: Select(N.getOperand(0)); BuildMI(BB, V8::IMPLICIT_DEF, 0, cast(N)->getReg()); return; case ISD::EntryToken: return; // Noop case ISD::TokenFactor: for (unsigned i = 0, e = Node->getNumOperands(); i != e; ++i) Select(Node->getOperand(i)); return; case ISD::CopyToReg: Select(N.getOperand(0)); Tmp1 = SelectExpr(N.getOperand(1)); Tmp2 = cast(N)->getReg(); if (Tmp1 != Tmp2) { if (N.getOperand(1).getValueType() == MVT::f64 || N.getOperand(1).getValueType() == MVT::f32) BuildMI(BB, V8::FMOVS, 2, Tmp2).addReg(Tmp1); else BuildMI(BB, V8::ORrr, 2, Tmp2).addReg(Tmp1).addReg(V8::G0); } return; case ISD::RET: //FIXME: abort(); return; case ISD::TRUNCSTORE: case ISD::STORE: { SDOperand Chain = N.getOperand(0); SDOperand Value = N.getOperand(1); SDOperand Address = N.getOperand(2); Select(Chain); Tmp1 = SelectExpr(Value); Tmp2 = SelectExpr(Address); unsigned VT = opcode == ISD::STORE ? Value.getValueType() : cast(Node->getOperand(4))->getVT(); switch(VT) { default: assert(0 && "unknown Type in store"); case MVT::f64: Opc = V8::STDFrr; break; case MVT::f32: Opc = V8::STFrr; break; case MVT::i1: //FIXME: DAG does not promote this load case MVT::i8: Opc = V8::STBrr; break; case MVT::i16: Opc = V8::STHrr; break; case MVT::i32: Opc = V8::STLrr; break; case MVT::i64: Opc = V8::STDrr; break; } BuildMI(BB,Opc,2).addReg(Tmp1).addReg(Tmp2); return; } case ISD::EXTLOAD: case ISD::SEXTLOAD: case ISD::ZEXTLOAD: case ISD::LOAD: case ISD::CopyFromReg: case ISD::TAILCALL: case ISD::CALL: case ISD::DYNAMIC_STACKALLOC: ExprMap.erase(N); SelectExpr(N); return; case ISD::CALLSEQ_START: case ISD::CALLSEQ_END: Select(N.getOperand(0)); Tmp1 = cast(N.getOperand(1))->getValue(); Opc = N.getOpcode() == ISD::CALLSEQ_START ? V8::ADJUSTCALLSTACKDOWN : V8::ADJUSTCALLSTACKUP; BuildMI(BB, Opc, 1).addImm(Tmp1); return; } assert(0 && "Should not be reached!"); } /// createV8PatternInstructionSelector - This pass converts an LLVM function /// into a machine code representation using pattern matching and a machine /// description file. /// FunctionPass *llvm::createV8PatternInstructionSelector(TargetMachine &TM) { return new ISel(TM); } #endif