BasicBlock* Decompiler::decompileBasicBlock(MachineBasicBlock *MBB, Function *F) { // Create a Selection DAG of MachineSDNodes DAG = createDAGFromMachineBasicBlock(MBB); if (ViewMCDAGs) { MBB->print(Infos); DAG->viewGraph(MBB->getName()); } // Run the engine to decompile into SDNodes InvISel->SetDAG(DAG); DAG->AssignTopologicalOrder(); // This sets the use on the first node and prevents root from being deleted. HandleSDNode Dummy(DAG->getRoot()); // Start at root and go to entry token SelectionDAG::allnodes_iterator ISelPosition(DAG->getRoot().getNode()); ++ISelPosition; // Make sure that ISelPosition gets properly updated when nodes are deleted // in calls made from this function. ISelUpdater ISU(*DAG, ISelPosition); while (ISelPosition != DAG->allnodes_begin()) { SDNode *Node = --ISelPosition; for (SelectionDAG::allnodes_iterator beg = DAG->allnodes_begin(), end = DAG->allnodes_end(); beg != end; ++beg) { DEBUG(errs() << "Current Node: ";); DEBUG(Node->dump()); DEBUG(beg->dump()); } // Skip dead nodes // if (Node->use_empty()) // continue; SDNode *ResNode = InvISel->Transmogrify(Node); if (ResNode == Node || Node->getOpcode() == ISD::DELETED_NODE) continue; if (ResNode) { DAG->ReplaceAllUsesWith(Node, ResNode); } if (Node->use_empty()) { DAG->RemoveDeadNode(Node); } }
/// This is the main entry point for the type legalizer. This does a top-down /// traversal of the dag, legalizing types as it goes. Returns "true" if it made /// any changes. bool DAGTypeLegalizer::run() { bool Changed = false; // Create a dummy node (which is not added to allnodes), that adds a reference // to the root node, preventing it from being deleted, and tracking any // changes of the root. HandleSDNode Dummy(DAG.getRoot()); Dummy.setNodeId(Unanalyzed); // The root of the dag may dangle to deleted nodes until the type legalizer is // done. Set it to null to avoid confusion. DAG.setRoot(SDValue()); // Walk all nodes in the graph, assigning them a NodeId of 'ReadyToProcess' // (and remembering them) if they are leaves and assigning 'Unanalyzed' if // non-leaves. for (SDNode &Node : DAG.allnodes()) { if (Node.getNumOperands() == 0) { AddToWorklist(&Node); } else { Node.setNodeId(Unanalyzed); } } // Now that we have a set of nodes to process, handle them all. while (!Worklist.empty()) { #ifndef EXPENSIVE_CHECKS if (EnableExpensiveChecks) #endif PerformExpensiveChecks(); SDNode *N = Worklist.back(); Worklist.pop_back(); assert(N->getNodeId() == ReadyToProcess && "Node should be ready if on worklist!"); if (IgnoreNodeResults(N)) goto ScanOperands; // Scan the values produced by the node, checking to see if any result // types are illegal. for (unsigned i = 0, NumResults = N->getNumValues(); i < NumResults; ++i) { EVT ResultVT = N->getValueType(i); switch (getTypeAction(ResultVT)) { case TargetLowering::TypeLegal: break; // The following calls must take care of *all* of the node's results, // not just the illegal result they were passed (this includes results // with a legal type). Results can be remapped using ReplaceValueWith, // or their promoted/expanded/etc values registered in PromotedIntegers, // ExpandedIntegers etc. case TargetLowering::TypePromoteInteger: PromoteIntegerResult(N, i); Changed = true; goto NodeDone; case TargetLowering::TypeExpandInteger: ExpandIntegerResult(N, i); Changed = true; goto NodeDone; case TargetLowering::TypeSoftenFloat: Changed = SoftenFloatResult(N, i); if (Changed) goto NodeDone; // If not changed, the result type should be legally in register. assert(isLegalInHWReg(ResultVT) && "Unchanged SoftenFloatResult should be legal in register!"); goto ScanOperands; case TargetLowering::TypeExpandFloat: ExpandFloatResult(N, i); Changed = true; goto NodeDone; case TargetLowering::TypeScalarizeVector: ScalarizeVectorResult(N, i); Changed = true; goto NodeDone; case TargetLowering::TypeSplitVector: SplitVectorResult(N, i); Changed = true; goto NodeDone; case TargetLowering::TypeWidenVector: WidenVectorResult(N, i); Changed = true; goto NodeDone; case TargetLowering::TypePromoteFloat: PromoteFloatResult(N, i); Changed = true; goto NodeDone; } } ScanOperands: // Scan the operand list for the node, handling any nodes with operands that // are illegal. { unsigned NumOperands = N->getNumOperands(); bool NeedsReanalyzing = false; unsigned i; for (i = 0; i != NumOperands; ++i) { if (IgnoreNodeResults(N->getOperand(i).getNode())) continue; EVT OpVT = N->getOperand(i).getValueType(); switch (getTypeAction(OpVT)) { case TargetLowering::TypeLegal: continue; // The following calls must either replace all of the node's results // using ReplaceValueWith, and return "false"; or update the node's // operands in place, and return "true". case TargetLowering::TypePromoteInteger: NeedsReanalyzing = PromoteIntegerOperand(N, i); Changed = true; break; case TargetLowering::TypeExpandInteger: NeedsReanalyzing = ExpandIntegerOperand(N, i); Changed = true; break; case TargetLowering::TypeSoftenFloat: NeedsReanalyzing = SoftenFloatOperand(N, i); Changed = true; break; case TargetLowering::TypeExpandFloat: NeedsReanalyzing = ExpandFloatOperand(N, i); Changed = true; break; case TargetLowering::TypeScalarizeVector: NeedsReanalyzing = ScalarizeVectorOperand(N, i); Changed = true; break; case TargetLowering::TypeSplitVector: NeedsReanalyzing = SplitVectorOperand(N, i); Changed = true; break; case TargetLowering::TypeWidenVector: NeedsReanalyzing = WidenVectorOperand(N, i); Changed = true; break; case TargetLowering::TypePromoteFloat: NeedsReanalyzing = PromoteFloatOperand(N, i); Changed = true; break; } break; } // The sub-method updated N in place. Check to see if any operands are new, // and if so, mark them. If the node needs revisiting, don't add all users // to the worklist etc. if (NeedsReanalyzing) { assert(N->getNodeId() == ReadyToProcess && "Node ID recalculated?"); N->setNodeId(NewNode); // Recompute the NodeId and correct processed operands, adding the node to // the worklist if ready. SDNode *M = AnalyzeNewNode(N); if (M == N) // The node didn't morph - nothing special to do, it will be revisited. continue; // The node morphed - this is equivalent to legalizing by replacing every // value of N with the corresponding value of M. So do that now. assert(N->getNumValues() == M->getNumValues() && "Node morphing changed the number of results!"); for (unsigned i = 0, e = N->getNumValues(); i != e; ++i) // Replacing the value takes care of remapping the new value. ReplaceValueWith(SDValue(N, i), SDValue(M, i)); assert(N->getNodeId() == NewNode && "Unexpected node state!"); // The node continues to live on as part of the NewNode fungus that // grows on top of the useful nodes. Nothing more needs to be done // with it - move on to the next node. continue; } if (i == NumOperands) { DEBUG(dbgs() << "Legally typed node: "; N->dump(&DAG); dbgs() << "\n"); } } NodeDone: // If we reach here, the node was processed, potentially creating new nodes. // Mark it as processed and add its users to the worklist as appropriate. assert(N->getNodeId() == ReadyToProcess && "Node ID recalculated?"); N->setNodeId(Processed); for (SDNode::use_iterator UI = N->use_begin(), E = N->use_end(); UI != E; ++UI) { SDNode *User = *UI; int NodeId = User->getNodeId(); // This node has two options: it can either be a new node or its Node ID // may be a count of the number of operands it has that are not ready. if (NodeId > 0) { User->setNodeId(NodeId-1); // If this was the last use it was waiting on, add it to the ready list. if (NodeId-1 == ReadyToProcess) Worklist.push_back(User); continue; } // If this is an unreachable new node, then ignore it. If it ever becomes // reachable by being used by a newly created node then it will be handled // by AnalyzeNewNode. if (NodeId == NewNode) continue; // Otherwise, this node is new: this is the first operand of it that // became ready. Its new NodeId is the number of operands it has minus 1 // (as this node is now processed). assert(NodeId == Unanalyzed && "Unknown node ID!"); User->setNodeId(User->getNumOperands() - 1); // If the node only has a single operand, it is now ready. if (User->getNumOperands() == 1) Worklist.push_back(User); } }
/// Select instructions not customized! Used for /// expanded, promoted and normal instructions SDNode* MBlazeDAGToDAGISel::Select(SDNode *Node) { unsigned Opcode = Node->getOpcode(); SDLoc dl(Node); // If we have a custom node, we already have selected! if (Node->isMachineOpcode()) return NULL; /// // Instruction Selection not handled by the auto-generated // tablegen selection should be handled here. /// switch (Opcode) { default: break; // Get target GOT address. case ISD::GLOBAL_OFFSET_TABLE: return getGlobalBaseReg(); case ISD::FrameIndex: { SDValue imm = CurDAG->getTargetConstant(0, MVT::i32); int FI = dyn_cast<FrameIndexSDNode>(Node)->getIndex(); EVT VT = Node->getValueType(0); SDValue TFI = CurDAG->getTargetFrameIndex(FI, VT); unsigned Opc = MBlaze::ADDIK; if (Node->hasOneUse()) return CurDAG->SelectNodeTo(Node, Opc, VT, TFI, imm); return CurDAG->getMachineNode(Opc, dl, VT, TFI, imm); } /// Handle direct and indirect calls when using PIC. On PIC, when /// GOT is smaller than about 64k (small code) the GA target is /// loaded with only one instruction. Otherwise GA's target must /// be loaded with 3 instructions. case MBlazeISD::JmpLink: { if (TM.getRelocationModel() == Reloc::PIC_) { SDValue Chain = Node->getOperand(0); SDValue Callee = Node->getOperand(1); SDValue R20Reg = CurDAG->getRegister(MBlaze::R20, MVT::i32); SDValue InFlag(0, 0); if ((isa<GlobalAddressSDNode>(Callee)) || (isa<ExternalSymbolSDNode>(Callee))) { /// Direct call for global addresses and external symbols SDValue GPReg = CurDAG->getRegister(MBlaze::R15, MVT::i32); // Use load to get GOT target SDValue Ops[] = { Callee, GPReg, Chain }; SDValue Load = SDValue(CurDAG->getMachineNode(MBlaze::LW, dl, MVT::i32, MVT::Other, Ops), 0); Chain = Load.getValue(1); // Call target must be on T9 Chain = CurDAG->getCopyToReg(Chain, dl, R20Reg, Load, InFlag); } else /// Indirect call Chain = CurDAG->getCopyToReg(Chain, dl, R20Reg, Callee, InFlag); // Emit Jump and Link Register SDNode *ResNode = CurDAG->getMachineNode(MBlaze::BRLID, dl, MVT::Other, MVT::Glue, R20Reg, Chain); Chain = SDValue(ResNode, 0); InFlag = SDValue(ResNode, 1); ReplaceUses(SDValue(Node, 0), Chain); ReplaceUses(SDValue(Node, 1), InFlag); return ResNode; } } } // Select the default instruction SDNode *ResNode = SelectCode(Node); DEBUG(errs() << "=> "); if (ResNode == NULL || ResNode == Node) DEBUG(Node->dump(CurDAG)); else DEBUG(ResNode->dump(CurDAG)); DEBUG(errs() << "\n"); return ResNode; }
// Select - Convert the specified operand from a target-independent to a // target-specific node if it hasn't already been changed. SDNode *IA64DAGToDAGISel::Select(SDValue Op) { SDNode *N = Op.getNode(); if (N->isMachineOpcode()) return NULL; // Already selected. DebugLoc dl = Op.getDebugLoc(); switch (N->getOpcode()) { default: break; case IA64ISD::BRCALL: { // XXX: this is also a hack! SDValue Chain = N->getOperand(0); SDValue InFlag; // Null incoming flag value. if(N->getNumOperands()==3) { // we have an incoming chain, callee and flag InFlag = N->getOperand(2); } unsigned CallOpcode; SDValue CallOperand; // if we can call directly, do so if (GlobalAddressSDNode *GASD = dyn_cast<GlobalAddressSDNode>(N->getOperand(1))) { CallOpcode = IA64::BRCALL_IPREL_GA; CallOperand = CurDAG->getTargetGlobalAddress(GASD->getGlobal(), MVT::i64); } else if (isa<ExternalSymbolSDNode>(N->getOperand(1))) { // FIXME: we currently NEED this case for correctness, to avoid // "non-pic code with imm reloc.n against dynamic symbol" errors CallOpcode = IA64::BRCALL_IPREL_ES; CallOperand = N->getOperand(1); } else { // otherwise we need to load the function descriptor, // load the branch target (function)'s entry point and GP, // branch (call) then restore the GP SDValue FnDescriptor = N->getOperand(1); // load the branch target's entry point [mem] and // GP value [mem+8] SDValue targetEntryPoint= SDValue(CurDAG->getTargetNode(IA64::LD8, dl, MVT::i64, MVT::Other, FnDescriptor, CurDAG->getEntryNode()), 0); Chain = targetEntryPoint.getValue(1); SDValue targetGPAddr= SDValue(CurDAG->getTargetNode(IA64::ADDS, dl, MVT::i64, FnDescriptor, CurDAG->getConstant(8, MVT::i64)), 0); Chain = targetGPAddr.getValue(1); SDValue targetGP = SDValue(CurDAG->getTargetNode(IA64::LD8, dl, MVT::i64,MVT::Other, targetGPAddr, CurDAG->getEntryNode()), 0); Chain = targetGP.getValue(1); Chain = CurDAG->getCopyToReg(Chain, dl, IA64::r1, targetGP, InFlag); InFlag = Chain.getValue(1); Chain = CurDAG->getCopyToReg(Chain, dl, IA64::B6, targetEntryPoint, InFlag); // FLAG these? InFlag = Chain.getValue(1); CallOperand = CurDAG->getRegister(IA64::B6, MVT::i64); CallOpcode = IA64::BRCALL_INDIRECT; } // Finally, once everything is setup, emit the call itself if (InFlag.getNode()) Chain = SDValue(CurDAG->getTargetNode(CallOpcode, dl, MVT::Other, MVT::Flag, CallOperand, InFlag), 0); else // there might be no arguments Chain = SDValue(CurDAG->getTargetNode(CallOpcode, dl, MVT::Other, MVT::Flag, CallOperand, Chain), 0); InFlag = Chain.getValue(1); std::vector<SDValue> CallResults; CallResults.push_back(Chain); CallResults.push_back(InFlag); for (unsigned i = 0, e = CallResults.size(); i != e; ++i) ReplaceUses(Op.getValue(i), CallResults[i]); return NULL; } case IA64ISD::GETFD: { SDValue Input = N->getOperand(0); return CurDAG->getTargetNode(IA64::GETFD, dl, MVT::i64, Input); } case ISD::FDIV: case ISD::SDIV: case ISD::UDIV: case ISD::SREM: case ISD::UREM: return SelectDIV(Op); case ISD::TargetConstantFP: { SDValue Chain = CurDAG->getEntryNode(); // this is a constant, so.. SDValue V; ConstantFPSDNode* N2 = cast<ConstantFPSDNode>(N); if (N2->getValueAPF().isPosZero()) { V = CurDAG->getCopyFromReg(Chain, dl, IA64::F0, MVT::f64); } else if (N2->isExactlyValue(N2->getValueType(0) == MVT::f32 ? APFloat(+1.0f) : APFloat(+1.0))) { V = CurDAG->getCopyFromReg(Chain, dl, IA64::F1, MVT::f64); } else assert(0 && "Unexpected FP constant!"); ReplaceUses(SDValue(N, 0), V); return 0; } case ISD::FrameIndex: { // TODO: reduce creepyness int FI = cast<FrameIndexSDNode>(N)->getIndex(); if (N->hasOneUse()) return CurDAG->SelectNodeTo(N, IA64::MOV, MVT::i64, CurDAG->getTargetFrameIndex(FI, MVT::i64)); else return CurDAG->getTargetNode(IA64::MOV, dl, MVT::i64, CurDAG->getTargetFrameIndex(FI, MVT::i64)); } case ISD::ConstantPool: { // TODO: nuke the constant pool // (ia64 doesn't need one) ConstantPoolSDNode *CP = cast<ConstantPoolSDNode>(N); Constant *C = CP->getConstVal(); SDValue CPI = CurDAG->getTargetConstantPool(C, MVT::i64, CP->getAlignment()); return CurDAG->getTargetNode(IA64::ADDL_GA, dl, MVT::i64, // ? CurDAG->getRegister(IA64::r1, MVT::i64), CPI); } case ISD::GlobalAddress: { GlobalValue *GV = cast<GlobalAddressSDNode>(N)->getGlobal(); SDValue GA = CurDAG->getTargetGlobalAddress(GV, MVT::i64); SDValue Tmp = SDValue(CurDAG->getTargetNode(IA64::ADDL_GA, dl, MVT::i64, CurDAG->getRegister(IA64::r1, MVT::i64), GA), 0); return CurDAG->getTargetNode(IA64::LD8, dl, MVT::i64, MVT::Other, Tmp, CurDAG->getEntryNode()); } /* XXX case ISD::ExternalSymbol: { SDValue EA = CurDAG->getTargetExternalSymbol( cast<ExternalSymbolSDNode>(N)->getSymbol(), MVT::i64); SDValue Tmp = CurDAG->getTargetNode(IA64::ADDL_EA, dl, MVT::i64, CurDAG->getRegister(IA64::r1, MVT::i64), EA); return CurDAG->getTargetNode(IA64::LD8, dl, MVT::i64, Tmp); } */ case ISD::LOAD: { // FIXME: load -1, not 1, for bools? LoadSDNode *LD = cast<LoadSDNode>(N); SDValue Chain = LD->getChain(); SDValue Address = LD->getBasePtr(); MVT TypeBeingLoaded = LD->getMemoryVT(); unsigned Opc; switch (TypeBeingLoaded.getSimpleVT()) { default: #ifndef NDEBUG N->dump(CurDAG); #endif assert(0 && "Cannot load this type!"); case MVT::i1: { // this is a bool Opc = IA64::LD1; // first we load a byte, then compare for != 0 if(N->getValueType(0) == MVT::i1) { // XXX: early exit! return CurDAG->SelectNodeTo(N, IA64::CMPNE, MVT::i1, MVT::Other, SDValue(CurDAG->getTargetNode(Opc, dl, MVT::i64, Address), 0), CurDAG->getRegister(IA64::r0, MVT::i64), Chain); } /* otherwise, we want to load a bool into something bigger: LD1 will do that for us, so we just fall through */ } case MVT::i8: Opc = IA64::LD1; break; case MVT::i16: Opc = IA64::LD2; break; case MVT::i32: Opc = IA64::LD4; break; case MVT::i64: Opc = IA64::LD8; break; case MVT::f32: Opc = IA64::LDF4; break; case MVT::f64: Opc = IA64::LDF8; break; } // TODO: comment this return CurDAG->SelectNodeTo(N, Opc, N->getValueType(0), MVT::Other, Address, Chain); } case ISD::STORE: { StoreSDNode *ST = cast<StoreSDNode>(N); SDValue Address = ST->getBasePtr(); SDValue Chain = ST->getChain(); unsigned Opc; if (ISD::isNON_TRUNCStore(N)) { switch (N->getOperand(1).getValueType().getSimpleVT()) { default: assert(0 && "unknown type in store"); case MVT::i1: { // this is a bool Opc = IA64::ST1; // we store either 0 or 1 as a byte // first load zero! SDValue Initial = CurDAG->getCopyFromReg(Chain, dl, IA64::r0, MVT::i64); Chain = Initial.getValue(1); // then load 1 into the same reg iff the predicate to store is 1 SDValue Tmp = ST->getValue(); Tmp = SDValue(CurDAG->getTargetNode(IA64::TPCADDS, dl, MVT::i64, Initial, CurDAG->getTargetConstant(1, MVT::i64), Tmp), 0); return CurDAG->SelectNodeTo(N, Opc, MVT::Other, Address, Tmp, Chain); } case MVT::i64: Opc = IA64::ST8; break; case MVT::f64: Opc = IA64::STF8; break; } } else { // Truncating store switch(ST->getMemoryVT().getSimpleVT()) { default: assert(0 && "unknown type in truncstore"); case MVT::i8: Opc = IA64::ST1; break; case MVT::i16: Opc = IA64::ST2; break; case MVT::i32: Opc = IA64::ST4; break; case MVT::f32: Opc = IA64::STF4; break; } } SDValue N1 = N->getOperand(1); SDValue N2 = N->getOperand(2); return CurDAG->SelectNodeTo(N, Opc, MVT::Other, N2, N1, Chain); } case ISD::BRCOND: { SDValue Chain = N->getOperand(0); SDValue CC = N->getOperand(1); MachineBasicBlock *Dest = cast<BasicBlockSDNode>(N->getOperand(2))->getBasicBlock(); //FIXME - we do NOT need long branches all the time return CurDAG->SelectNodeTo(N, IA64::BRLCOND_NOTCALL, MVT::Other, CC, CurDAG->getBasicBlock(Dest), Chain); } case ISD::CALLSEQ_START: case ISD::CALLSEQ_END: { int64_t Amt = cast<ConstantSDNode>(N->getOperand(1))->getZExtValue(); unsigned Opc = N->getOpcode() == ISD::CALLSEQ_START ? IA64::ADJUSTCALLSTACKDOWN : IA64::ADJUSTCALLSTACKUP; SDValue N0 = N->getOperand(0); return CurDAG->SelectNodeTo(N, Opc, MVT::Other, getI64Imm(Amt), N0); } case ISD::BR: // FIXME: we don't need long branches all the time! SDValue N0 = N->getOperand(0); return CurDAG->SelectNodeTo(N, IA64::BRL_NOTCALL, MVT::Other, N->getOperand(1), N0); } return SelectCode(Op); }