Path: blob/main/contrib/llvm-project/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp
35271 views
//===- XtensaISelLowering.cpp - Xtensa DAG Lowering Implementation --------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file defines the interfaces that Xtensa uses to lower LLVM code into a9// selection DAG.10//11//===----------------------------------------------------------------------===//1213#include "XtensaISelLowering.h"14#include "XtensaConstantPoolValue.h"15#include "XtensaSubtarget.h"16#include "XtensaTargetMachine.h"17#include "llvm/CodeGen/CallingConvLower.h"18#include "llvm/CodeGen/MachineFrameInfo.h"19#include "llvm/CodeGen/MachineInstrBuilder.h"20#include "llvm/CodeGen/MachineJumpTableInfo.h"21#include "llvm/CodeGen/MachineRegisterInfo.h"22#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"23#include "llvm/Support/Debug.h"24#include "llvm/Support/ErrorHandling.h"25#include "llvm/Support/MathExtras.h"26#include "llvm/Support/raw_ostream.h"27#include <deque>2829using namespace llvm;3031#define DEBUG_TYPE "xtensa-lower"3233// Return true if we must use long (in fact, indirect) function call.34// It's simplified version, production implimentation must35// resolve a functions in ROM (usually glibc functions)36static bool isLongCall(const char *str) {37// Currently always use long calls38return true;39}4041XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &TM,42const XtensaSubtarget &STI)43: TargetLowering(TM), Subtarget(STI) {44MVT PtrVT = MVT::i32;45// Set up the register classes.46addRegisterClass(MVT::i32, &Xtensa::ARRegClass);4748// Set up special registers.49setStackPointerRegisterToSaveRestore(Xtensa::SP);5051setSchedulingPreference(Sched::RegPressure);5253setMinFunctionAlignment(Align(4));5455setOperationAction(ISD::Constant, MVT::i32, Custom);56setOperationAction(ISD::Constant, MVT::i64, Expand);5758setBooleanContents(ZeroOrOneBooleanContent);5960setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand);61setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i8, Expand);62setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i16, Expand);6364setOperationAction(ISD::BITCAST, MVT::i32, Expand);65setOperationAction(ISD::BITCAST, MVT::f32, Expand);66setOperationAction(ISD::UINT_TO_FP, MVT::i32, Expand);67setOperationAction(ISD::SINT_TO_FP, MVT::i32, Expand);68setOperationAction(ISD::FP_TO_UINT, MVT::i32, Expand);69setOperationAction(ISD::FP_TO_SINT, MVT::i32, Expand);7071// No sign extend instructions for i172for (MVT VT : MVT::integer_valuetypes()) {73setLoadExtAction(ISD::SEXTLOAD, VT, MVT::i1, Promote);74setLoadExtAction(ISD::ZEXTLOAD, VT, MVT::i1, Promote);75setLoadExtAction(ISD::EXTLOAD, VT, MVT::i1, Promote);76}7778setOperationAction(ISD::ConstantPool, PtrVT, Custom);79setOperationAction(ISD::GlobalAddress, PtrVT, Custom);80setOperationAction(ISD::BlockAddress, PtrVT, Custom);81setOperationAction(ISD::JumpTable, PtrVT, Custom);8283// Expand jump table branches as address arithmetic followed by an84// indirect jump.85setOperationAction(ISD::BR_JT, MVT::Other, Custom);8687setOperationAction(ISD::BR_CC, MVT::i32, Legal);88setOperationAction(ISD::BR_CC, MVT::i64, Expand);89setOperationAction(ISD::BR_CC, MVT::f32, Expand);9091setOperationAction(ISD::SELECT, MVT::i32, Expand);92setOperationAction(ISD::SELECT_CC, MVT::i32, Custom);93setOperationAction(ISD::SETCC, MVT::i32, Expand);9495setCondCodeAction(ISD::SETGT, MVT::i32, Expand);96setCondCodeAction(ISD::SETLE, MVT::i32, Expand);97setCondCodeAction(ISD::SETUGT, MVT::i32, Expand);98setCondCodeAction(ISD::SETULE, MVT::i32, Expand);99100// Implement custom stack allocations101setOperationAction(ISD::DYNAMIC_STACKALLOC, PtrVT, Custom);102// Implement custom stack save and restore103setOperationAction(ISD::STACKSAVE, MVT::Other, Custom);104setOperationAction(ISD::STACKRESTORE, MVT::Other, Custom);105106// Compute derived properties from the register classes107computeRegisterProperties(STI.getRegisterInfo());108}109110bool XtensaTargetLowering::isOffsetFoldingLegal(111const GlobalAddressSDNode *GA) const {112// The Xtensa target isn't yet aware of offsets.113return false;114}115116//===----------------------------------------------------------------------===//117// Calling conventions118//===----------------------------------------------------------------------===//119120#include "XtensaGenCallingConv.inc"121122static bool CC_Xtensa_Custom(unsigned ValNo, MVT ValVT, MVT LocVT,123CCValAssign::LocInfo LocInfo,124ISD::ArgFlagsTy ArgFlags, CCState &State) {125static const MCPhysReg IntRegs[] = {Xtensa::A2, Xtensa::A3, Xtensa::A4,126Xtensa::A5, Xtensa::A6, Xtensa::A7};127128if (ArgFlags.isByVal()) {129Align ByValAlign = ArgFlags.getNonZeroByValAlign();130unsigned ByValSize = ArgFlags.getByValSize();131if (ByValSize < 4) {132ByValSize = 4;133}134if (ByValAlign < Align(4)) {135ByValAlign = Align(4);136}137unsigned Offset = State.AllocateStack(ByValSize, ByValAlign);138State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo));139// Mark all unused registers as allocated to avoid misuse140// of such registers.141while (State.AllocateReg(IntRegs))142;143return false;144}145146// Promote i8 and i16147if (LocVT == MVT::i8 || LocVT == MVT::i16) {148LocVT = MVT::i32;149if (ArgFlags.isSExt())150LocInfo = CCValAssign::SExt;151else if (ArgFlags.isZExt())152LocInfo = CCValAssign::ZExt;153else154LocInfo = CCValAssign::AExt;155}156157unsigned Register;158159Align OrigAlign = ArgFlags.getNonZeroOrigAlign();160bool needs64BitAlign = (ValVT == MVT::i32 && OrigAlign == Align(8));161bool needs128BitAlign = (ValVT == MVT::i32 && OrigAlign == Align(16));162163if (ValVT == MVT::i32) {164Register = State.AllocateReg(IntRegs);165// If this is the first part of an i64 arg,166// the allocated register must be either A2, A4 or A6.167if (needs64BitAlign && (Register == Xtensa::A3 || Register == Xtensa::A5 ||168Register == Xtensa::A7))169Register = State.AllocateReg(IntRegs);170// arguments with 16byte alignment must be passed in the first register or171// passed via stack172if (needs128BitAlign && (Register != Xtensa::A2))173while ((Register = State.AllocateReg(IntRegs)))174;175LocVT = MVT::i32;176} else if (ValVT == MVT::f64) {177// Allocate int register and shadow next int register.178Register = State.AllocateReg(IntRegs);179if (Register == Xtensa::A3 || Register == Xtensa::A5 ||180Register == Xtensa::A7)181Register = State.AllocateReg(IntRegs);182State.AllocateReg(IntRegs);183LocVT = MVT::i32;184} else {185report_fatal_error("Cannot handle this ValVT.");186}187188if (!Register) {189unsigned Offset = State.AllocateStack(ValVT.getStoreSize(), OrigAlign);190State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo));191} else {192State.addLoc(CCValAssign::getReg(ValNo, ValVT, Register, LocVT, LocInfo));193}194195return false;196}197198CCAssignFn *XtensaTargetLowering::CCAssignFnForCall(CallingConv::ID CC,199bool IsVarArg) const {200return CC_Xtensa_Custom;201}202203SDValue XtensaTargetLowering::LowerFormalArguments(204SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,205const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL,206SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {207MachineFunction &MF = DAG.getMachineFunction();208MachineFrameInfo &MFI = MF.getFrameInfo();209210// Used with vargs to acumulate store chains.211std::vector<SDValue> OutChains;212213if (IsVarArg)214report_fatal_error("Var arg not supported by FormalArguments Lowering");215216// Assign locations to all of the incoming arguments.217SmallVector<CCValAssign, 16> ArgLocs;218CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), ArgLocs,219*DAG.getContext());220221CCInfo.AnalyzeFormalArguments(Ins, CCAssignFnForCall(CallConv, IsVarArg));222223for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {224CCValAssign &VA = ArgLocs[i];225// Arguments stored on registers226if (VA.isRegLoc()) {227EVT RegVT = VA.getLocVT();228const TargetRegisterClass *RC;229230if (RegVT == MVT::i32)231RC = &Xtensa::ARRegClass;232else233report_fatal_error("RegVT not supported by FormalArguments Lowering");234235// Transform the arguments stored on236// physical registers into virtual ones237unsigned Register = MF.addLiveIn(VA.getLocReg(), RC);238SDValue ArgValue = DAG.getCopyFromReg(Chain, DL, Register, RegVT);239240// If this is an 8 or 16-bit value, it has been passed promoted241// to 32 bits. Insert an assert[sz]ext to capture this, then242// truncate to the right size.243if (VA.getLocInfo() != CCValAssign::Full) {244unsigned Opcode = 0;245if (VA.getLocInfo() == CCValAssign::SExt)246Opcode = ISD::AssertSext;247else if (VA.getLocInfo() == CCValAssign::ZExt)248Opcode = ISD::AssertZext;249if (Opcode)250ArgValue = DAG.getNode(Opcode, DL, RegVT, ArgValue,251DAG.getValueType(VA.getValVT()));252ArgValue = DAG.getNode((VA.getValVT() == MVT::f32) ? ISD::BITCAST253: ISD::TRUNCATE,254DL, VA.getValVT(), ArgValue);255}256257InVals.push_back(ArgValue);258259} else {260assert(VA.isMemLoc());261262EVT ValVT = VA.getValVT();263264// The stack pointer offset is relative to the caller stack frame.265int FI = MFI.CreateFixedObject(ValVT.getStoreSize(), VA.getLocMemOffset(),266true);267268if (Ins[VA.getValNo()].Flags.isByVal()) {269// Assume that in this case load operation is created270SDValue FIN = DAG.getFrameIndex(FI, MVT::i32);271InVals.push_back(FIN);272} else {273// Create load nodes to retrieve arguments from the stack274SDValue FIN =275DAG.getFrameIndex(FI, getFrameIndexTy(DAG.getDataLayout()));276InVals.push_back(DAG.getLoad(277ValVT, DL, Chain, FIN,278MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), FI)));279}280}281}282283// All stores are grouped in one node to allow the matching between284// the size of Ins and InVals. This only happens when on varg functions285if (!OutChains.empty()) {286OutChains.push_back(Chain);287Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, OutChains);288}289290return Chain;291}292293SDValue294XtensaTargetLowering::LowerCall(CallLoweringInfo &CLI,295SmallVectorImpl<SDValue> &InVals) const {296SelectionDAG &DAG = CLI.DAG;297SDLoc &DL = CLI.DL;298SmallVector<ISD::OutputArg, 32> &Outs = CLI.Outs;299SmallVector<SDValue, 32> &OutVals = CLI.OutVals;300SmallVector<ISD::InputArg, 32> &Ins = CLI.Ins;301SDValue Chain = CLI.Chain;302SDValue Callee = CLI.Callee;303bool &IsTailCall = CLI.IsTailCall;304CallingConv::ID CallConv = CLI.CallConv;305bool IsVarArg = CLI.IsVarArg;306307MachineFunction &MF = DAG.getMachineFunction();308EVT PtrVT = getPointerTy(DAG.getDataLayout());309const TargetFrameLowering *TFL = Subtarget.getFrameLowering();310311// TODO: Support tail call optimization.312IsTailCall = false;313314// Analyze the operands of the call, assigning locations to each operand.315SmallVector<CCValAssign, 16> ArgLocs;316CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());317318CCAssignFn *CC = CCAssignFnForCall(CallConv, IsVarArg);319320CCInfo.AnalyzeCallOperands(Outs, CC);321322// Get a count of how many bytes are to be pushed on the stack.323unsigned NumBytes = CCInfo.getStackSize();324325Align StackAlignment = TFL->getStackAlign();326unsigned NextStackOffset = alignTo(NumBytes, StackAlignment);327328Chain = DAG.getCALLSEQ_START(Chain, NextStackOffset, 0, DL);329330// Copy argument values to their designated locations.331std::deque<std::pair<unsigned, SDValue>> RegsToPass;332SmallVector<SDValue, 8> MemOpChains;333SDValue StackPtr;334for (unsigned I = 0, E = ArgLocs.size(); I != E; ++I) {335CCValAssign &VA = ArgLocs[I];336SDValue ArgValue = OutVals[I];337ISD::ArgFlagsTy Flags = Outs[I].Flags;338339if (VA.isRegLoc())340// Queue up the argument copies and emit them at the end.341RegsToPass.push_back(std::make_pair(VA.getLocReg(), ArgValue));342else if (Flags.isByVal()) {343assert(VA.isMemLoc());344assert(Flags.getByValSize() &&345"ByVal args of size 0 should have been ignored by front-end.");346assert(!IsTailCall &&347"Do not tail-call optimize if there is a byval argument.");348349if (!StackPtr.getNode())350StackPtr = DAG.getCopyFromReg(Chain, DL, Xtensa::SP, PtrVT);351unsigned Offset = VA.getLocMemOffset();352SDValue Address = DAG.getNode(ISD::ADD, DL, PtrVT, StackPtr,353DAG.getIntPtrConstant(Offset, DL));354SDValue SizeNode = DAG.getConstant(Flags.getByValSize(), DL, MVT::i32);355SDValue Memcpy = DAG.getMemcpy(356Chain, DL, Address, ArgValue, SizeNode, Flags.getNonZeroByValAlign(),357/*isVolatile=*/false, /*AlwaysInline=*/false,358/*CI=*/nullptr, std::nullopt, MachinePointerInfo(), MachinePointerInfo());359MemOpChains.push_back(Memcpy);360} else {361assert(VA.isMemLoc() && "Argument not register or memory");362363// Work out the address of the stack slot. Unpromoted ints and364// floats are passed as right-justified 8-byte values.365if (!StackPtr.getNode())366StackPtr = DAG.getCopyFromReg(Chain, DL, Xtensa::SP, PtrVT);367unsigned Offset = VA.getLocMemOffset();368SDValue Address = DAG.getNode(ISD::ADD, DL, PtrVT, StackPtr,369DAG.getIntPtrConstant(Offset, DL));370371// Emit the store.372MemOpChains.push_back(373DAG.getStore(Chain, DL, ArgValue, Address, MachinePointerInfo()));374}375}376377// Join the stores, which are independent of one another.378if (!MemOpChains.empty())379Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, MemOpChains);380381// Build a sequence of copy-to-reg nodes, chained and glued together.382SDValue Glue;383for (unsigned I = 0, E = RegsToPass.size(); I != E; ++I) {384unsigned Reg = RegsToPass[I].first;385Chain = DAG.getCopyToReg(Chain, DL, Reg, RegsToPass[I].second, Glue);386Glue = Chain.getValue(1);387}388std::string name;389unsigned char TF = 0;390391// Accept direct calls by converting symbolic call addresses to the392// associated Target* opcodes.393if (ExternalSymbolSDNode *E = dyn_cast<ExternalSymbolSDNode>(Callee)) {394name = E->getSymbol();395TF = E->getTargetFlags();396if (isPositionIndependent()) {397report_fatal_error("PIC relocations is not supported");398} else399Callee = DAG.getTargetExternalSymbol(E->getSymbol(), PtrVT, TF);400} else if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) {401const GlobalValue *GV = G->getGlobal();402name = GV->getName().str();403}404405if ((!name.empty()) && isLongCall(name.c_str())) {406// Create a constant pool entry for the callee address407XtensaCP::XtensaCPModifier Modifier = XtensaCP::no_modifier;408409XtensaConstantPoolValue *CPV = XtensaConstantPoolSymbol::Create(410*DAG.getContext(), name.c_str(), 0 /* XtensaCLabelIndex */, false,411Modifier);412413// Get the address of the callee into a register414SDValue CPAddr = DAG.getTargetConstantPool(CPV, PtrVT, Align(4), 0, TF);415SDValue CPWrap = getAddrPCRel(CPAddr, DAG);416Callee = CPWrap;417}418419// The first call operand is the chain and the second is the target address.420SmallVector<SDValue, 8> Ops;421Ops.push_back(Chain);422Ops.push_back(Callee);423424// Add a register mask operand representing the call-preserved registers.425const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo();426const uint32_t *Mask = TRI->getCallPreservedMask(MF, CallConv);427assert(Mask && "Missing call preserved mask for calling convention");428Ops.push_back(DAG.getRegisterMask(Mask));429430// Add argument registers to the end of the list so that they are431// known live into the call.432for (unsigned I = 0, E = RegsToPass.size(); I != E; ++I) {433unsigned Reg = RegsToPass[I].first;434Ops.push_back(DAG.getRegister(Reg, RegsToPass[I].second.getValueType()));435}436437// Glue the call to the argument copies, if any.438if (Glue.getNode())439Ops.push_back(Glue);440441SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);442Chain = DAG.getNode(XtensaISD::CALL, DL, NodeTys, Ops);443Glue = Chain.getValue(1);444445// Mark the end of the call, which is glued to the call itself.446Chain = DAG.getCALLSEQ_END(Chain, DAG.getConstant(NumBytes, DL, PtrVT, true),447DAG.getConstant(0, DL, PtrVT, true), Glue, DL);448Glue = Chain.getValue(1);449450// Assign locations to each value returned by this call.451SmallVector<CCValAssign, 16> RetLocs;452CCState RetCCInfo(CallConv, IsVarArg, MF, RetLocs, *DAG.getContext());453RetCCInfo.AnalyzeCallResult(Ins, RetCC_Xtensa);454455// Copy all of the result registers out of their specified physreg.456for (unsigned I = 0, E = RetLocs.size(); I != E; ++I) {457CCValAssign &VA = RetLocs[I];458459// Copy the value out, gluing the copy to the end of the call sequence.460unsigned Reg = VA.getLocReg();461SDValue RetValue = DAG.getCopyFromReg(Chain, DL, Reg, VA.getLocVT(), Glue);462Chain = RetValue.getValue(1);463Glue = RetValue.getValue(2);464465InVals.push_back(RetValue);466}467return Chain;468}469470bool XtensaTargetLowering::CanLowerReturn(471CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg,472const SmallVectorImpl<ISD::OutputArg> &Outs, LLVMContext &Context) const {473SmallVector<CCValAssign, 16> RVLocs;474CCState CCInfo(CallConv, IsVarArg, MF, RVLocs, Context);475return CCInfo.CheckReturn(Outs, RetCC_Xtensa);476}477478SDValue479XtensaTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,480bool IsVarArg,481const SmallVectorImpl<ISD::OutputArg> &Outs,482const SmallVectorImpl<SDValue> &OutVals,483const SDLoc &DL, SelectionDAG &DAG) const {484if (IsVarArg)485report_fatal_error("VarArg not supported");486487MachineFunction &MF = DAG.getMachineFunction();488489// Assign locations to each returned value.490SmallVector<CCValAssign, 16> RetLocs;491CCState RetCCInfo(CallConv, IsVarArg, MF, RetLocs, *DAG.getContext());492RetCCInfo.AnalyzeReturn(Outs, RetCC_Xtensa);493494SDValue Glue;495// Quick exit for void returns496if (RetLocs.empty())497return DAG.getNode(XtensaISD::RET, DL, MVT::Other, Chain);498499// Copy the result values into the output registers.500SmallVector<SDValue, 4> RetOps;501RetOps.push_back(Chain);502for (unsigned I = 0, E = RetLocs.size(); I != E; ++I) {503CCValAssign &VA = RetLocs[I];504SDValue RetValue = OutVals[I];505506// Make the return register live on exit.507assert(VA.isRegLoc() && "Can only return in registers!");508509// Chain and glue the copies together.510unsigned Register = VA.getLocReg();511Chain = DAG.getCopyToReg(Chain, DL, Register, RetValue, Glue);512Glue = Chain.getValue(1);513RetOps.push_back(DAG.getRegister(Register, VA.getLocVT()));514}515516// Update chain and glue.517RetOps[0] = Chain;518if (Glue.getNode())519RetOps.push_back(Glue);520521return DAG.getNode(XtensaISD::RET, DL, MVT::Other, RetOps);522}523524static unsigned getBranchOpcode(ISD::CondCode Cond) {525switch (Cond) {526case ISD::SETEQ:527return Xtensa::BEQ;528case ISD::SETNE:529return Xtensa::BNE;530case ISD::SETLT:531return Xtensa::BLT;532case ISD::SETLE:533return Xtensa::BGE;534case ISD::SETGT:535return Xtensa::BLT;536case ISD::SETGE:537return Xtensa::BGE;538case ISD::SETULT:539return Xtensa::BLTU;540case ISD::SETULE:541return Xtensa::BGEU;542case ISD::SETUGT:543return Xtensa::BLTU;544case ISD::SETUGE:545return Xtensa::BGEU;546default:547llvm_unreachable("Unknown branch kind");548}549}550551SDValue XtensaTargetLowering::LowerSELECT_CC(SDValue Op,552SelectionDAG &DAG) const {553SDLoc DL(Op);554EVT Ty = Op.getOperand(0).getValueType();555SDValue LHS = Op.getOperand(0);556SDValue RHS = Op.getOperand(1);557SDValue TrueValue = Op.getOperand(2);558SDValue FalseValue = Op.getOperand(3);559ISD::CondCode CC = cast<CondCodeSDNode>(Op->getOperand(4))->get();560561unsigned BrOpcode = getBranchOpcode(CC);562SDValue TargetCC = DAG.getConstant(BrOpcode, DL, MVT::i32);563564return DAG.getNode(XtensaISD::SELECT_CC, DL, Ty, LHS, RHS, TrueValue,565FalseValue, TargetCC);566}567568SDValue XtensaTargetLowering::LowerImmediate(SDValue Op,569SelectionDAG &DAG) const {570const ConstantSDNode *CN = cast<ConstantSDNode>(Op);571SDLoc DL(CN);572APInt APVal = CN->getAPIntValue();573int64_t Value = APVal.getSExtValue();574if (Op.getValueType() == MVT::i32) {575// Check if use node maybe lowered to the MOVI instruction576if (Value > -2048 && Value <= 2047)577return Op;578// Check if use node maybe lowered to the ADDMI instruction579SDNode &OpNode = *Op.getNode();580if ((OpNode.hasOneUse() && OpNode.use_begin()->getOpcode() == ISD::ADD) &&581isShiftedInt<16, 8>(Value))582return Op;583Type *Ty = Type::getInt32Ty(*DAG.getContext());584Constant *CV = ConstantInt::get(Ty, Value);585SDValue CP = DAG.getConstantPool(CV, MVT::i32);586return CP;587}588return Op;589}590591SDValue XtensaTargetLowering::LowerGlobalAddress(SDValue Op,592SelectionDAG &DAG) const {593const GlobalAddressSDNode *G = cast<GlobalAddressSDNode>(Op);594SDLoc DL(Op);595auto PtrVT = Op.getValueType();596const GlobalValue *GV = G->getGlobal();597598SDValue CPAddr = DAG.getTargetConstantPool(GV, PtrVT, Align(4));599SDValue CPWrap = getAddrPCRel(CPAddr, DAG);600601return CPWrap;602}603604SDValue XtensaTargetLowering::LowerBlockAddress(SDValue Op,605SelectionDAG &DAG) const {606BlockAddressSDNode *Node = cast<BlockAddressSDNode>(Op);607const BlockAddress *BA = Node->getBlockAddress();608EVT PtrVT = Op.getValueType();609610XtensaConstantPoolValue *CPV =611XtensaConstantPoolConstant::Create(BA, 0, XtensaCP::CPBlockAddress);612SDValue CPAddr = DAG.getTargetConstantPool(CPV, PtrVT, Align(4));613SDValue CPWrap = getAddrPCRel(CPAddr, DAG);614615return CPWrap;616}617618SDValue XtensaTargetLowering::LowerBR_JT(SDValue Op, SelectionDAG &DAG) const {619SDValue Chain = Op.getOperand(0);620SDValue Table = Op.getOperand(1);621SDValue Index = Op.getOperand(2);622SDLoc DL(Op);623JumpTableSDNode *JT = cast<JumpTableSDNode>(Table);624MachineFunction &MF = DAG.getMachineFunction();625const MachineJumpTableInfo *MJTI = MF.getJumpTableInfo();626SDValue TargetJT = DAG.getTargetJumpTable(JT->getIndex(), MVT::i32);627const DataLayout &TD = DAG.getDataLayout();628EVT PtrVT = Table.getValueType();629unsigned EntrySize = MJTI->getEntrySize(TD);630631Index = DAG.getNode(ISD::MUL, DL, Index.getValueType(), Index,632DAG.getConstant(EntrySize, DL, Index.getValueType()));633SDValue Addr = DAG.getNode(ISD::ADD, DL, Index.getValueType(), Index, Table);634SDValue LD =635DAG.getLoad(PtrVT, DL, Chain, Addr,636MachinePointerInfo::getJumpTable(DAG.getMachineFunction()));637638return DAG.getNode(XtensaISD::BR_JT, DL, MVT::Other, LD.getValue(1), LD,639TargetJT);640}641642SDValue XtensaTargetLowering::LowerJumpTable(SDValue Op,643SelectionDAG &DAG) const {644JumpTableSDNode *JT = cast<JumpTableSDNode>(Op);645EVT PtrVT = Op.getValueType();646647// Create a constant pool entry for the callee address648XtensaConstantPoolValue *CPV =649XtensaConstantPoolJumpTable::Create(*DAG.getContext(), JT->getIndex());650651// Get the address of the callee into a register652SDValue CPAddr = DAG.getTargetConstantPool(CPV, PtrVT, Align(4));653654return getAddrPCRel(CPAddr, DAG);655}656657SDValue XtensaTargetLowering::getAddrPCRel(SDValue Op,658SelectionDAG &DAG) const {659SDLoc DL(Op);660EVT Ty = Op.getValueType();661return DAG.getNode(XtensaISD::PCREL_WRAPPER, DL, Ty, Op);662}663664SDValue XtensaTargetLowering::LowerConstantPool(ConstantPoolSDNode *CP,665SelectionDAG &DAG) const {666EVT PtrVT = getPointerTy(DAG.getDataLayout());667SDValue Result;668if (!CP->isMachineConstantPoolEntry()) {669Result = DAG.getTargetConstantPool(CP->getConstVal(), PtrVT, CP->getAlign(),670CP->getOffset());671} else {672report_fatal_error("This constantpool type is not supported yet");673}674675return getAddrPCRel(Result, DAG);676}677678SDValue XtensaTargetLowering::LowerSTACKSAVE(SDValue Op,679SelectionDAG &DAG) const {680return DAG.getCopyFromReg(Op.getOperand(0), SDLoc(Op), Xtensa::SP,681Op.getValueType());682}683684SDValue XtensaTargetLowering::LowerSTACKRESTORE(SDValue Op,685SelectionDAG &DAG) const {686return DAG.getCopyToReg(Op.getOperand(0), SDLoc(Op), Xtensa::SP,687Op.getOperand(1));688}689690SDValue XtensaTargetLowering::LowerDYNAMIC_STACKALLOC(SDValue Op,691SelectionDAG &DAG) const {692SDValue Chain = Op.getOperand(0); // Legalize the chain.693SDValue Size = Op.getOperand(1); // Legalize the size.694EVT VT = Size->getValueType(0);695SDLoc DL(Op);696697// Round up Size to 32698SDValue SizeTmp =699DAG.getNode(ISD::ADD, DL, VT, Size, DAG.getConstant(31, DL, MVT::i32));700SDValue SizeRoundUp = DAG.getNode(ISD::AND, DL, VT, SizeTmp,701DAG.getConstant(~31, DL, MVT::i32));702703unsigned SPReg = Xtensa::SP;704SDValue SP = DAG.getCopyFromReg(Chain, DL, SPReg, VT);705SDValue NewSP = DAG.getNode(ISD::SUB, DL, VT, SP, SizeRoundUp); // Value706Chain = DAG.getCopyToReg(SP.getValue(1), DL, SPReg, NewSP); // Output chain707708SDValue NewVal = DAG.getCopyFromReg(Chain, DL, SPReg, MVT::i32);709Chain = NewVal.getValue(1);710711SDValue Ops[2] = {NewVal, Chain};712return DAG.getMergeValues(Ops, DL);713}714715SDValue XtensaTargetLowering::LowerOperation(SDValue Op,716SelectionDAG &DAG) const {717switch (Op.getOpcode()) {718case ISD::BR_JT:719return LowerBR_JT(Op, DAG);720case ISD::Constant:721return LowerImmediate(Op, DAG);722case ISD::GlobalAddress:723return LowerGlobalAddress(Op, DAG);724case ISD::BlockAddress:725return LowerBlockAddress(Op, DAG);726case ISD::JumpTable:727return LowerJumpTable(Op, DAG);728case ISD::ConstantPool:729return LowerConstantPool(cast<ConstantPoolSDNode>(Op), DAG);730case ISD::SELECT_CC:731return LowerSELECT_CC(Op, DAG);732case ISD::STACKSAVE:733return LowerSTACKSAVE(Op, DAG);734case ISD::STACKRESTORE:735return LowerSTACKRESTORE(Op, DAG);736case ISD::DYNAMIC_STACKALLOC:737return LowerDYNAMIC_STACKALLOC(Op, DAG);738default:739report_fatal_error("Unexpected node to lower");740}741}742743const char *XtensaTargetLowering::getTargetNodeName(unsigned Opcode) const {744switch (Opcode) {745case XtensaISD::BR_JT:746return "XtensaISD::BR_JT";747case XtensaISD::CALL:748return "XtensaISD::CALL";749case XtensaISD::PCREL_WRAPPER:750return "XtensaISD::PCREL_WRAPPER";751case XtensaISD::RET:752return "XtensaISD::RET";753case XtensaISD::SELECT_CC:754return "XtensaISD::SELECT_CC";755}756return nullptr;757}758759//===----------------------------------------------------------------------===//760// Custom insertion761//===----------------------------------------------------------------------===//762763MachineBasicBlock *764XtensaTargetLowering::emitSelectCC(MachineInstr &MI,765MachineBasicBlock *MBB) const {766const TargetInstrInfo &TII = *Subtarget.getInstrInfo();767DebugLoc DL = MI.getDebugLoc();768769MachineOperand &LHS = MI.getOperand(1);770MachineOperand &RHS = MI.getOperand(2);771MachineOperand &TrueValue = MI.getOperand(3);772MachineOperand &FalseValue = MI.getOperand(4);773unsigned BrKind = MI.getOperand(5).getImm();774775// To "insert" a SELECT_CC instruction, we actually have to insert776// CopyMBB and SinkMBB blocks and add branch to MBB. We build phi777// operation in SinkMBB like phi (TrueVakue,FalseValue), where TrueValue778// is passed from MMB and FalseValue is passed from CopyMBB.779// MBB780// | \781// | CopyMBB782// | /783// SinkMBB784// The incoming instruction knows the785// destination vreg to set, the condition code register to branch on, the786// true/false values to select between, and a branch opcode to use.787const BasicBlock *LLVM_BB = MBB->getBasicBlock();788MachineFunction::iterator It = ++MBB->getIterator();789790MachineFunction *F = MBB->getParent();791MachineBasicBlock *CopyMBB = F->CreateMachineBasicBlock(LLVM_BB);792MachineBasicBlock *SinkMBB = F->CreateMachineBasicBlock(LLVM_BB);793794F->insert(It, CopyMBB);795F->insert(It, SinkMBB);796797// Transfer the remainder of MBB and its successor edges to SinkMBB.798SinkMBB->splice(SinkMBB->begin(), MBB,799std::next(MachineBasicBlock::iterator(MI)), MBB->end());800SinkMBB->transferSuccessorsAndUpdatePHIs(MBB);801802MBB->addSuccessor(CopyMBB);803MBB->addSuccessor(SinkMBB);804805BuildMI(MBB, DL, TII.get(BrKind))806.addReg(LHS.getReg())807.addReg(RHS.getReg())808.addMBB(SinkMBB);809810CopyMBB->addSuccessor(SinkMBB);811812// SinkMBB:813// %Result = phi [ %FalseValue, CopyMBB ], [ %TrueValue, MBB ]814// ...815816BuildMI(*SinkMBB, SinkMBB->begin(), DL, TII.get(Xtensa::PHI),817MI.getOperand(0).getReg())818.addReg(FalseValue.getReg())819.addMBB(CopyMBB)820.addReg(TrueValue.getReg())821.addMBB(MBB);822823MI.eraseFromParent(); // The pseudo instruction is gone now.824return SinkMBB;825}826827MachineBasicBlock *XtensaTargetLowering::EmitInstrWithCustomInserter(828MachineInstr &MI, MachineBasicBlock *MBB) const {829switch (MI.getOpcode()) {830case Xtensa::SELECT:831return emitSelectCC(MI, MBB);832default:833llvm_unreachable("Unexpected instr type to insert");834}835}836837838