//===- XtensaISelLowering.cpp - Xtensa DAG Lowering Implementation --------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file defines the interfaces that Xtensa uses to lower LLVM code into a // selection DAG. // //===----------------------------------------------------------------------===// #include "XtensaISelLowering.h" #include "XtensaConstantPoolValue.h" #include "XtensaSubtarget.h" #include "XtensaTargetMachine.h" #include "llvm/CodeGen/CallingConvLower.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineJumpTableInfo.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" #include using namespace llvm; #define DEBUG_TYPE "xtensa-lower" // Return true if we must use long (in fact, indirect) function call. // It's simplified version, production implimentation must // resolve a functions in ROM (usually glibc functions) static bool isLongCall(const char *str) { // Currently always use long calls return true; } XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &TM, const XtensaSubtarget &STI) : TargetLowering(TM), Subtarget(STI) { MVT PtrVT = MVT::i32; // Set up the register classes. addRegisterClass(MVT::i32, &Xtensa::ARRegClass); // Set up special registers. setStackPointerRegisterToSaveRestore(Xtensa::SP); setSchedulingPreference(Sched::RegPressure); setMinFunctionAlignment(Align(4)); setOperationAction(ISD::Constant, MVT::i32, Custom); setOperationAction(ISD::Constant, MVT::i64, Expand); setBooleanContents(ZeroOrOneBooleanContent); 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::BITCAST, MVT::i32, Expand); setOperationAction(ISD::BITCAST, MVT::f32, Expand); setOperationAction(ISD::UINT_TO_FP, MVT::i32, Expand); setOperationAction(ISD::SINT_TO_FP, MVT::i32, Expand); setOperationAction(ISD::FP_TO_UINT, MVT::i32, Expand); setOperationAction(ISD::FP_TO_SINT, MVT::i32, Expand); // No sign extend instructions for i1 for (MVT VT : MVT::integer_valuetypes()) { setLoadExtAction(ISD::SEXTLOAD, VT, MVT::i1, Promote); setLoadExtAction(ISD::ZEXTLOAD, VT, MVT::i1, Promote); setLoadExtAction(ISD::EXTLOAD, VT, MVT::i1, Promote); } setOperationAction(ISD::ConstantPool, PtrVT, Custom); setOperationAction(ISD::GlobalAddress, PtrVT, Custom); setOperationAction(ISD::BlockAddress, PtrVT, Custom); setOperationAction(ISD::JumpTable, PtrVT, Custom); // Expand jump table branches as address arithmetic followed by an // indirect jump. setOperationAction(ISD::BR_JT, MVT::Other, Custom); setOperationAction(ISD::BR_CC, MVT::i32, Legal); setOperationAction(ISD::BR_CC, MVT::i64, Expand); setOperationAction(ISD::BR_CC, MVT::f32, Expand); setOperationAction(ISD::SELECT, MVT::i32, Expand); setOperationAction(ISD::SELECT_CC, MVT::i32, Custom); setOperationAction(ISD::SETCC, MVT::i32, Expand); setCondCodeAction(ISD::SETGT, MVT::i32, Expand); setCondCodeAction(ISD::SETLE, MVT::i32, Expand); setCondCodeAction(ISD::SETUGT, MVT::i32, Expand); setCondCodeAction(ISD::SETULE, MVT::i32, Expand); // Implement custom stack allocations setOperationAction(ISD::DYNAMIC_STACKALLOC, PtrVT, Custom); // Implement custom stack save and restore setOperationAction(ISD::STACKSAVE, MVT::Other, Custom); setOperationAction(ISD::STACKRESTORE, MVT::Other, Custom); // Compute derived properties from the register classes computeRegisterProperties(STI.getRegisterInfo()); } bool XtensaTargetLowering::isOffsetFoldingLegal( const GlobalAddressSDNode *GA) const { // The Xtensa target isn't yet aware of offsets. return false; } //===----------------------------------------------------------------------===// // Calling conventions //===----------------------------------------------------------------------===// #include "XtensaGenCallingConv.inc" static bool CC_Xtensa_Custom(unsigned ValNo, MVT ValVT, MVT LocVT, CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags, CCState &State) { static const MCPhysReg IntRegs[] = {Xtensa::A2, Xtensa::A3, Xtensa::A4, Xtensa::A5, Xtensa::A6, Xtensa::A7}; if (ArgFlags.isByVal()) { Align ByValAlign = ArgFlags.getNonZeroByValAlign(); unsigned ByValSize = ArgFlags.getByValSize(); if (ByValSize < 4) { ByValSize = 4; } if (ByValAlign < Align(4)) { ByValAlign = Align(4); } unsigned Offset = State.AllocateStack(ByValSize, ByValAlign); State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo)); // Mark all unused registers as allocated to avoid misuse // of such registers. while (State.AllocateReg(IntRegs)) ; return false; } // Promote i8 and i16 if (LocVT == MVT::i8 || LocVT == MVT::i16) { LocVT = MVT::i32; if (ArgFlags.isSExt()) LocInfo = CCValAssign::SExt; else if (ArgFlags.isZExt()) LocInfo = CCValAssign::ZExt; else LocInfo = CCValAssign::AExt; } unsigned Register; Align OrigAlign = ArgFlags.getNonZeroOrigAlign(); bool needs64BitAlign = (ValVT == MVT::i32 && OrigAlign == Align(8)); bool needs128BitAlign = (ValVT == MVT::i32 && OrigAlign == Align(16)); if (ValVT == MVT::i32) { Register = State.AllocateReg(IntRegs); // If this is the first part of an i64 arg, // the allocated register must be either A2, A4 or A6. if (needs64BitAlign && (Register == Xtensa::A3 || Register == Xtensa::A5 || Register == Xtensa::A7)) Register = State.AllocateReg(IntRegs); // arguments with 16byte alignment must be passed in the first register or // passed via stack if (needs128BitAlign && (Register != Xtensa::A2)) while ((Register = State.AllocateReg(IntRegs))) ; LocVT = MVT::i32; } else if (ValVT == MVT::f64) { // Allocate int register and shadow next int register. Register = State.AllocateReg(IntRegs); if (Register == Xtensa::A3 || Register == Xtensa::A5 || Register == Xtensa::A7) Register = State.AllocateReg(IntRegs); State.AllocateReg(IntRegs); LocVT = MVT::i32; } else { report_fatal_error("Cannot handle this ValVT."); } if (!Register) { unsigned Offset = State.AllocateStack(ValVT.getStoreSize(), OrigAlign); State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo)); } else { State.addLoc(CCValAssign::getReg(ValNo, ValVT, Register, LocVT, LocInfo)); } return false; } CCAssignFn *XtensaTargetLowering::CCAssignFnForCall(CallingConv::ID CC, bool IsVarArg) const { return CC_Xtensa_Custom; } SDValue XtensaTargetLowering::LowerFormalArguments( SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, const SmallVectorImpl &Ins, const SDLoc &DL, SelectionDAG &DAG, SmallVectorImpl &InVals) const { MachineFunction &MF = DAG.getMachineFunction(); MachineFrameInfo &MFI = MF.getFrameInfo(); // Used with vargs to acumulate store chains. std::vector OutChains; if (IsVarArg) report_fatal_error("Var arg not supported by FormalArguments Lowering"); // Assign locations to all of the incoming arguments. SmallVector ArgLocs; CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), ArgLocs, *DAG.getContext()); CCInfo.AnalyzeFormalArguments(Ins, CCAssignFnForCall(CallConv, IsVarArg)); for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { CCValAssign &VA = ArgLocs[i]; // Arguments stored on registers if (VA.isRegLoc()) { EVT RegVT = VA.getLocVT(); const TargetRegisterClass *RC; if (RegVT == MVT::i32) RC = &Xtensa::ARRegClass; else report_fatal_error("RegVT not supported by FormalArguments Lowering"); // Transform the arguments stored on // physical registers into virtual ones unsigned Register = MF.addLiveIn(VA.getLocReg(), RC); SDValue ArgValue = DAG.getCopyFromReg(Chain, DL, Register, RegVT); // If this is an 8 or 16-bit value, it has been passed promoted // to 32 bits. Insert an assert[sz]ext to capture this, then // truncate to the right size. if (VA.getLocInfo() != CCValAssign::Full) { unsigned Opcode = 0; if (VA.getLocInfo() == CCValAssign::SExt) Opcode = ISD::AssertSext; else if (VA.getLocInfo() == CCValAssign::ZExt) Opcode = ISD::AssertZext; if (Opcode) ArgValue = DAG.getNode(Opcode, DL, RegVT, ArgValue, DAG.getValueType(VA.getValVT())); ArgValue = DAG.getNode((VA.getValVT() == MVT::f32) ? ISD::BITCAST : ISD::TRUNCATE, DL, VA.getValVT(), ArgValue); } InVals.push_back(ArgValue); } else { assert(VA.isMemLoc()); EVT ValVT = VA.getValVT(); // The stack pointer offset is relative to the caller stack frame. int FI = MFI.CreateFixedObject(ValVT.getStoreSize(), VA.getLocMemOffset(), true); if (Ins[VA.getValNo()].Flags.isByVal()) { // Assume that in this case load operation is created SDValue FIN = DAG.getFrameIndex(FI, MVT::i32); InVals.push_back(FIN); } else { // Create load nodes to retrieve arguments from the stack SDValue FIN = DAG.getFrameIndex(FI, getFrameIndexTy(DAG.getDataLayout())); InVals.push_back(DAG.getLoad( ValVT, DL, Chain, FIN, MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), FI))); } } } // All stores are grouped in one node to allow the matching between // the size of Ins and InVals. This only happens when on varg functions if (!OutChains.empty()) { OutChains.push_back(Chain); Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, OutChains); } return Chain; } SDValue XtensaTargetLowering::LowerCall(CallLoweringInfo &CLI, SmallVectorImpl &InVals) const { SelectionDAG &DAG = CLI.DAG; SDLoc &DL = CLI.DL; SmallVector &Outs = CLI.Outs; SmallVector &OutVals = CLI.OutVals; SmallVector &Ins = CLI.Ins; SDValue Chain = CLI.Chain; SDValue Callee = CLI.Callee; bool &IsTailCall = CLI.IsTailCall; CallingConv::ID CallConv = CLI.CallConv; bool IsVarArg = CLI.IsVarArg; MachineFunction &MF = DAG.getMachineFunction(); EVT PtrVT = getPointerTy(DAG.getDataLayout()); const TargetFrameLowering *TFL = Subtarget.getFrameLowering(); // TODO: Support tail call optimization. IsTailCall = false; // Analyze the operands of the call, assigning locations to each operand. SmallVector ArgLocs; CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext()); CCAssignFn *CC = CCAssignFnForCall(CallConv, IsVarArg); CCInfo.AnalyzeCallOperands(Outs, CC); // Get a count of how many bytes are to be pushed on the stack. unsigned NumBytes = CCInfo.getStackSize(); Align StackAlignment = TFL->getStackAlign(); unsigned NextStackOffset = alignTo(NumBytes, StackAlignment); Chain = DAG.getCALLSEQ_START(Chain, NextStackOffset, 0, DL); // Copy argument values to their designated locations. std::deque> RegsToPass; SmallVector MemOpChains; SDValue StackPtr; for (unsigned I = 0, E = ArgLocs.size(); I != E; ++I) { CCValAssign &VA = ArgLocs[I]; SDValue ArgValue = OutVals[I]; ISD::ArgFlagsTy Flags = Outs[I].Flags; if (VA.isRegLoc()) // Queue up the argument copies and emit them at the end. RegsToPass.push_back(std::make_pair(VA.getLocReg(), ArgValue)); else if (Flags.isByVal()) { assert(VA.isMemLoc()); assert(Flags.getByValSize() && "ByVal args of size 0 should have been ignored by front-end."); assert(!IsTailCall && "Do not tail-call optimize if there is a byval argument."); if (!StackPtr.getNode()) StackPtr = DAG.getCopyFromReg(Chain, DL, Xtensa::SP, PtrVT); unsigned Offset = VA.getLocMemOffset(); SDValue Address = DAG.getNode(ISD::ADD, DL, PtrVT, StackPtr, DAG.getIntPtrConstant(Offset, DL)); SDValue SizeNode = DAG.getConstant(Flags.getByValSize(), DL, MVT::i32); SDValue Memcpy = DAG.getMemcpy( Chain, DL, Address, ArgValue, SizeNode, Flags.getNonZeroByValAlign(), /*isVolatile=*/false, /*AlwaysInline=*/false, /*CI=*/nullptr, std::nullopt, MachinePointerInfo(), MachinePointerInfo()); MemOpChains.push_back(Memcpy); } else { assert(VA.isMemLoc() && "Argument not register or memory"); // Work out the address of the stack slot. Unpromoted ints and // floats are passed as right-justified 8-byte values. if (!StackPtr.getNode()) StackPtr = DAG.getCopyFromReg(Chain, DL, Xtensa::SP, PtrVT); unsigned Offset = VA.getLocMemOffset(); SDValue Address = DAG.getNode(ISD::ADD, DL, PtrVT, StackPtr, DAG.getIntPtrConstant(Offset, DL)); // Emit the store. MemOpChains.push_back( DAG.getStore(Chain, DL, ArgValue, Address, MachinePointerInfo())); } } // Join the stores, which are independent of one another. if (!MemOpChains.empty()) Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, MemOpChains); // Build a sequence of copy-to-reg nodes, chained and glued together. SDValue Glue; for (unsigned I = 0, E = RegsToPass.size(); I != E; ++I) { unsigned Reg = RegsToPass[I].first; Chain = DAG.getCopyToReg(Chain, DL, Reg, RegsToPass[I].second, Glue); Glue = Chain.getValue(1); } std::string name; unsigned char TF = 0; // Accept direct calls by converting symbolic call addresses to the // associated Target* opcodes. if (ExternalSymbolSDNode *E = dyn_cast(Callee)) { name = E->getSymbol(); TF = E->getTargetFlags(); if (isPositionIndependent()) { report_fatal_error("PIC relocations is not supported"); } else Callee = DAG.getTargetExternalSymbol(E->getSymbol(), PtrVT, TF); } else if (GlobalAddressSDNode *G = dyn_cast(Callee)) { const GlobalValue *GV = G->getGlobal(); name = GV->getName().str(); } if ((!name.empty()) && isLongCall(name.c_str())) { // Create a constant pool entry for the callee address XtensaCP::XtensaCPModifier Modifier = XtensaCP::no_modifier; XtensaConstantPoolValue *CPV = XtensaConstantPoolSymbol::Create( *DAG.getContext(), name.c_str(), 0 /* XtensaCLabelIndex */, false, Modifier); // Get the address of the callee into a register SDValue CPAddr = DAG.getTargetConstantPool(CPV, PtrVT, Align(4), 0, TF); SDValue CPWrap = getAddrPCRel(CPAddr, DAG); Callee = CPWrap; } // The first call operand is the chain and the second is the target address. SmallVector Ops; Ops.push_back(Chain); Ops.push_back(Callee); // Add a register mask operand representing the call-preserved registers. const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo(); const uint32_t *Mask = TRI->getCallPreservedMask(MF, CallConv); assert(Mask && "Missing call preserved mask for calling convention"); Ops.push_back(DAG.getRegisterMask(Mask)); // 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) { unsigned Reg = RegsToPass[I].first; Ops.push_back(DAG.getRegister(Reg, RegsToPass[I].second.getValueType())); } // Glue the call to the argument copies, if any. if (Glue.getNode()) Ops.push_back(Glue); SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue); Chain = DAG.getNode(XtensaISD::CALL, DL, NodeTys, Ops); Glue = Chain.getValue(1); // Mark the end of the call, which is glued to the call itself. Chain = DAG.getCALLSEQ_END(Chain, DAG.getConstant(NumBytes, DL, PtrVT, true), DAG.getConstant(0, DL, PtrVT, true), Glue, DL); Glue = Chain.getValue(1); // Assign locations to each value returned by this call. SmallVector RetLocs; CCState RetCCInfo(CallConv, IsVarArg, MF, RetLocs, *DAG.getContext()); RetCCInfo.AnalyzeCallResult(Ins, RetCC_Xtensa); // Copy all of the result registers out of their specified physreg. for (unsigned I = 0, E = RetLocs.size(); I != E; ++I) { CCValAssign &VA = RetLocs[I]; // Copy the value out, gluing the copy to the end of the call sequence. unsigned Reg = VA.getLocReg(); SDValue RetValue = DAG.getCopyFromReg(Chain, DL, Reg, VA.getLocVT(), Glue); Chain = RetValue.getValue(1); Glue = RetValue.getValue(2); InVals.push_back(RetValue); } return Chain; } bool XtensaTargetLowering::CanLowerReturn( CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg, const SmallVectorImpl &Outs, LLVMContext &Context) const { SmallVector RVLocs; CCState CCInfo(CallConv, IsVarArg, MF, RVLocs, Context); return CCInfo.CheckReturn(Outs, RetCC_Xtensa); } SDValue XtensaTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, const SmallVectorImpl &Outs, const SmallVectorImpl &OutVals, const SDLoc &DL, SelectionDAG &DAG) const { if (IsVarArg) report_fatal_error("VarArg not supported"); MachineFunction &MF = DAG.getMachineFunction(); // Assign locations to each returned value. SmallVector RetLocs; CCState RetCCInfo(CallConv, IsVarArg, MF, RetLocs, *DAG.getContext()); RetCCInfo.AnalyzeReturn(Outs, RetCC_Xtensa); SDValue Glue; // Quick exit for void returns if (RetLocs.empty()) return DAG.getNode(XtensaISD::RET, DL, MVT::Other, Chain); // Copy the result values into the output registers. SmallVector RetOps; RetOps.push_back(Chain); for (unsigned I = 0, E = RetLocs.size(); I != E; ++I) { CCValAssign &VA = RetLocs[I]; SDValue RetValue = OutVals[I]; // Make the return register live on exit. assert(VA.isRegLoc() && "Can only return in registers!"); // Chain and glue the copies together. unsigned Register = VA.getLocReg(); Chain = DAG.getCopyToReg(Chain, DL, Register, RetValue, Glue); Glue = Chain.getValue(1); RetOps.push_back(DAG.getRegister(Register, VA.getLocVT())); } // Update chain and glue. RetOps[0] = Chain; if (Glue.getNode()) RetOps.push_back(Glue); return DAG.getNode(XtensaISD::RET, DL, MVT::Other, RetOps); } static unsigned getBranchOpcode(ISD::CondCode Cond) { switch (Cond) { case ISD::SETEQ: return Xtensa::BEQ; case ISD::SETNE: return Xtensa::BNE; case ISD::SETLT: return Xtensa::BLT; case ISD::SETLE: return Xtensa::BGE; case ISD::SETGT: return Xtensa::BLT; case ISD::SETGE: return Xtensa::BGE; case ISD::SETULT: return Xtensa::BLTU; case ISD::SETULE: return Xtensa::BGEU; case ISD::SETUGT: return Xtensa::BLTU; case ISD::SETUGE: return Xtensa::BGEU; default: llvm_unreachable("Unknown branch kind"); } } SDValue XtensaTargetLowering::LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const { SDLoc DL(Op); EVT Ty = Op.getOperand(0).getValueType(); SDValue LHS = Op.getOperand(0); SDValue RHS = Op.getOperand(1); SDValue TrueValue = Op.getOperand(2); SDValue FalseValue = Op.getOperand(3); ISD::CondCode CC = cast(Op->getOperand(4))->get(); unsigned BrOpcode = getBranchOpcode(CC); SDValue TargetCC = DAG.getConstant(BrOpcode, DL, MVT::i32); return DAG.getNode(XtensaISD::SELECT_CC, DL, Ty, LHS, RHS, TrueValue, FalseValue, TargetCC); } SDValue XtensaTargetLowering::LowerImmediate(SDValue Op, SelectionDAG &DAG) const { const ConstantSDNode *CN = cast(Op); SDLoc DL(CN); APInt APVal = CN->getAPIntValue(); int64_t Value = APVal.getSExtValue(); if (Op.getValueType() == MVT::i32) { // Check if use node maybe lowered to the MOVI instruction if (Value > -2048 && Value <= 2047) return Op; // Check if use node maybe lowered to the ADDMI instruction SDNode &OpNode = *Op.getNode(); if ((OpNode.hasOneUse() && OpNode.use_begin()->getOpcode() == ISD::ADD) && isShiftedInt<16, 8>(Value)) return Op; Type *Ty = Type::getInt32Ty(*DAG.getContext()); Constant *CV = ConstantInt::get(Ty, Value); SDValue CP = DAG.getConstantPool(CV, MVT::i32); return CP; } return Op; } SDValue XtensaTargetLowering::LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const { const GlobalAddressSDNode *G = cast(Op); SDLoc DL(Op); auto PtrVT = Op.getValueType(); const GlobalValue *GV = G->getGlobal(); SDValue CPAddr = DAG.getTargetConstantPool(GV, PtrVT, Align(4)); SDValue CPWrap = getAddrPCRel(CPAddr, DAG); return CPWrap; } SDValue XtensaTargetLowering::LowerBlockAddress(SDValue Op, SelectionDAG &DAG) const { BlockAddressSDNode *Node = cast(Op); const BlockAddress *BA = Node->getBlockAddress(); EVT PtrVT = Op.getValueType(); XtensaConstantPoolValue *CPV = XtensaConstantPoolConstant::Create(BA, 0, XtensaCP::CPBlockAddress); SDValue CPAddr = DAG.getTargetConstantPool(CPV, PtrVT, Align(4)); SDValue CPWrap = getAddrPCRel(CPAddr, DAG); return CPWrap; } SDValue XtensaTargetLowering::LowerBR_JT(SDValue Op, SelectionDAG &DAG) const { SDValue Chain = Op.getOperand(0); SDValue Table = Op.getOperand(1); SDValue Index = Op.getOperand(2); SDLoc DL(Op); JumpTableSDNode *JT = cast(Table); MachineFunction &MF = DAG.getMachineFunction(); const MachineJumpTableInfo *MJTI = MF.getJumpTableInfo(); SDValue TargetJT = DAG.getTargetJumpTable(JT->getIndex(), MVT::i32); const DataLayout &TD = DAG.getDataLayout(); EVT PtrVT = Table.getValueType(); unsigned EntrySize = MJTI->getEntrySize(TD); Index = DAG.getNode(ISD::MUL, DL, Index.getValueType(), Index, DAG.getConstant(EntrySize, DL, Index.getValueType())); SDValue Addr = DAG.getNode(ISD::ADD, DL, Index.getValueType(), Index, Table); SDValue LD = DAG.getLoad(PtrVT, DL, Chain, Addr, MachinePointerInfo::getJumpTable(DAG.getMachineFunction())); return DAG.getNode(XtensaISD::BR_JT, DL, MVT::Other, LD.getValue(1), LD, TargetJT); } SDValue XtensaTargetLowering::LowerJumpTable(SDValue Op, SelectionDAG &DAG) const { JumpTableSDNode *JT = cast(Op); EVT PtrVT = Op.getValueType(); // Create a constant pool entry for the callee address XtensaConstantPoolValue *CPV = XtensaConstantPoolJumpTable::Create(*DAG.getContext(), JT->getIndex()); // Get the address of the callee into a register SDValue CPAddr = DAG.getTargetConstantPool(CPV, PtrVT, Align(4)); return getAddrPCRel(CPAddr, DAG); } SDValue XtensaTargetLowering::getAddrPCRel(SDValue Op, SelectionDAG &DAG) const { SDLoc DL(Op); EVT Ty = Op.getValueType(); return DAG.getNode(XtensaISD::PCREL_WRAPPER, DL, Ty, Op); } SDValue XtensaTargetLowering::LowerConstantPool(ConstantPoolSDNode *CP, SelectionDAG &DAG) const { EVT PtrVT = getPointerTy(DAG.getDataLayout()); SDValue Result; if (!CP->isMachineConstantPoolEntry()) { Result = DAG.getTargetConstantPool(CP->getConstVal(), PtrVT, CP->getAlign(), CP->getOffset()); } else { report_fatal_error("This constantpool type is not supported yet"); } return getAddrPCRel(Result, DAG); } SDValue XtensaTargetLowering::LowerSTACKSAVE(SDValue Op, SelectionDAG &DAG) const { return DAG.getCopyFromReg(Op.getOperand(0), SDLoc(Op), Xtensa::SP, Op.getValueType()); } SDValue XtensaTargetLowering::LowerSTACKRESTORE(SDValue Op, SelectionDAG &DAG) const { return DAG.getCopyToReg(Op.getOperand(0), SDLoc(Op), Xtensa::SP, Op.getOperand(1)); } SDValue XtensaTargetLowering::LowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG) const { SDValue Chain = Op.getOperand(0); // Legalize the chain. SDValue Size = Op.getOperand(1); // Legalize the size. EVT VT = Size->getValueType(0); SDLoc DL(Op); // Round up Size to 32 SDValue SizeTmp = DAG.getNode(ISD::ADD, DL, VT, Size, DAG.getConstant(31, DL, MVT::i32)); SDValue SizeRoundUp = DAG.getNode(ISD::AND, DL, VT, SizeTmp, DAG.getConstant(~31, DL, MVT::i32)); unsigned SPReg = Xtensa::SP; SDValue SP = DAG.getCopyFromReg(Chain, DL, SPReg, VT); SDValue NewSP = DAG.getNode(ISD::SUB, DL, VT, SP, SizeRoundUp); // Value Chain = DAG.getCopyToReg(SP.getValue(1), DL, SPReg, NewSP); // Output chain SDValue NewVal = DAG.getCopyFromReg(Chain, DL, SPReg, MVT::i32); Chain = NewVal.getValue(1); SDValue Ops[2] = {NewVal, Chain}; return DAG.getMergeValues(Ops, DL); } SDValue XtensaTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const { switch (Op.getOpcode()) { case ISD::BR_JT: return LowerBR_JT(Op, DAG); case ISD::Constant: return LowerImmediate(Op, DAG); case ISD::GlobalAddress: return LowerGlobalAddress(Op, DAG); case ISD::BlockAddress: return LowerBlockAddress(Op, DAG); case ISD::JumpTable: return LowerJumpTable(Op, DAG); case ISD::ConstantPool: return LowerConstantPool(cast(Op), DAG); case ISD::SELECT_CC: return LowerSELECT_CC(Op, DAG); case ISD::STACKSAVE: return LowerSTACKSAVE(Op, DAG); case ISD::STACKRESTORE: return LowerSTACKRESTORE(Op, DAG); case ISD::DYNAMIC_STACKALLOC: return LowerDYNAMIC_STACKALLOC(Op, DAG); default: report_fatal_error("Unexpected node to lower"); } } const char *XtensaTargetLowering::getTargetNodeName(unsigned Opcode) const { switch (Opcode) { case XtensaISD::BR_JT: return "XtensaISD::BR_JT"; case XtensaISD::CALL: return "XtensaISD::CALL"; case XtensaISD::PCREL_WRAPPER: return "XtensaISD::PCREL_WRAPPER"; case XtensaISD::RET: return "XtensaISD::RET"; case XtensaISD::SELECT_CC: return "XtensaISD::SELECT_CC"; } return nullptr; } //===----------------------------------------------------------------------===// // Custom insertion //===----------------------------------------------------------------------===// MachineBasicBlock * XtensaTargetLowering::emitSelectCC(MachineInstr &MI, MachineBasicBlock *MBB) const { const TargetInstrInfo &TII = *Subtarget.getInstrInfo(); DebugLoc DL = MI.getDebugLoc(); MachineOperand &LHS = MI.getOperand(1); MachineOperand &RHS = MI.getOperand(2); MachineOperand &TrueValue = MI.getOperand(3); MachineOperand &FalseValue = MI.getOperand(4); unsigned BrKind = MI.getOperand(5).getImm(); // To "insert" a SELECT_CC instruction, we actually have to insert // CopyMBB and SinkMBB blocks and add branch to MBB. We build phi // operation in SinkMBB like phi (TrueVakue,FalseValue), where TrueValue // is passed from MMB and FalseValue is passed from CopyMBB. // MBB // | \ // | CopyMBB // | / // SinkMBB // The incoming instruction knows the // destination vreg to set, the condition code register to branch on, the // true/false values to select between, and a branch opcode to use. const BasicBlock *LLVM_BB = MBB->getBasicBlock(); MachineFunction::iterator It = ++MBB->getIterator(); MachineFunction *F = MBB->getParent(); MachineBasicBlock *CopyMBB = F->CreateMachineBasicBlock(LLVM_BB); MachineBasicBlock *SinkMBB = F->CreateMachineBasicBlock(LLVM_BB); F->insert(It, CopyMBB); F->insert(It, SinkMBB); // Transfer the remainder of MBB and its successor edges to SinkMBB. SinkMBB->splice(SinkMBB->begin(), MBB, std::next(MachineBasicBlock::iterator(MI)), MBB->end()); SinkMBB->transferSuccessorsAndUpdatePHIs(MBB); MBB->addSuccessor(CopyMBB); MBB->addSuccessor(SinkMBB); BuildMI(MBB, DL, TII.get(BrKind)) .addReg(LHS.getReg()) .addReg(RHS.getReg()) .addMBB(SinkMBB); CopyMBB->addSuccessor(SinkMBB); // SinkMBB: // %Result = phi [ %FalseValue, CopyMBB ], [ %TrueValue, MBB ] // ... BuildMI(*SinkMBB, SinkMBB->begin(), DL, TII.get(Xtensa::PHI), MI.getOperand(0).getReg()) .addReg(FalseValue.getReg()) .addMBB(CopyMBB) .addReg(TrueValue.getReg()) .addMBB(MBB); MI.eraseFromParent(); // The pseudo instruction is gone now. return SinkMBB; } MachineBasicBlock *XtensaTargetLowering::EmitInstrWithCustomInserter( MachineInstr &MI, MachineBasicBlock *MBB) const { switch (MI.getOpcode()) { case Xtensa::SELECT: return emitSelectCC(MI, MBB); default: llvm_unreachable("Unexpected instr type to insert"); } }