From 3a0dff0928f2e16a219b495cc20dab4ff6dd8709 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 28 Feb 2024 18:07:34 +0300 Subject: [PATCH 1/6] [Xtensa] Implement base CallConvention. Implement base Calling Convention functionality. Implement stack load/store register operations. --- llvm/lib/Target/Xtensa/CMakeLists.txt | 2 + llvm/lib/Target/Xtensa/Xtensa.td | 6 + llvm/lib/Target/Xtensa/XtensaCallingConv.td | 27 ++ llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp | 52 +++- llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 268 ++++++++++++++++++ llvm/lib/Target/Xtensa/XtensaISelLowering.h | 23 ++ llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp | 70 +++++ llvm/lib/Target/Xtensa/XtensaInstrInfo.h | 21 ++ llvm/lib/Target/Xtensa/XtensaInstrInfo.td | 8 +- llvm/lib/Target/Xtensa/XtensaOperators.td | 13 + llvm/lib/Target/Xtensa/XtensaRegisterInfo.cpp | 39 ++- llvm/lib/Target/Xtensa/XtensaUtils.cpp | 57 ++++ llvm/lib/Target/Xtensa/XtensaUtils.h | 27 ++ llvm/test/CodeGen/Xtensa/calling-conv.ll | 78 +++++ llvm/test/CodeGen/Xtensa/stack-access.ll | 35 +++ 15 files changed, 719 insertions(+), 7 deletions(-) create mode 100644 llvm/lib/Target/Xtensa/XtensaCallingConv.td create mode 100644 llvm/lib/Target/Xtensa/XtensaOperators.td create mode 100644 llvm/lib/Target/Xtensa/XtensaUtils.cpp create mode 100644 llvm/lib/Target/Xtensa/XtensaUtils.h create mode 100644 llvm/test/CodeGen/Xtensa/calling-conv.ll create mode 100644 llvm/test/CodeGen/Xtensa/stack-access.ll diff --git a/llvm/lib/Target/Xtensa/CMakeLists.txt b/llvm/lib/Target/Xtensa/CMakeLists.txt index 2064511e75b82..432b76d4fd576 100644 --- a/llvm/lib/Target/Xtensa/CMakeLists.txt +++ b/llvm/lib/Target/Xtensa/CMakeLists.txt @@ -4,6 +4,7 @@ set(LLVM_TARGET_DEFINITIONS Xtensa.td) tablegen(LLVM XtensaGenAsmMatcher.inc -gen-asm-matcher) tablegen(LLVM XtensaGenAsmWriter.inc -gen-asm-writer) +tablegen(LLVM XtensaGenCallingConv.inc -gen-callingconv) tablegen(LLVM XtensaGenDAGISel.inc -gen-dag-isel) tablegen(LLVM XtensaGenDisassemblerTables.inc -gen-disassembler) tablegen(LLVM XtensaGenInstrInfo.inc -gen-instr-info) @@ -22,6 +23,7 @@ add_llvm_target(XtensaCodeGen XtensaRegisterInfo.cpp XtensaSubtarget.cpp XtensaTargetMachine.cpp + XtensaUtils.cpp LINK_COMPONENTS AsmPrinter diff --git a/llvm/lib/Target/Xtensa/Xtensa.td b/llvm/lib/Target/Xtensa/Xtensa.td index b953540be94de..460a15e808b3a 100644 --- a/llvm/lib/Target/Xtensa/Xtensa.td +++ b/llvm/lib/Target/Xtensa/Xtensa.td @@ -35,6 +35,12 @@ def : Proc<"generic", []>; include "XtensaRegisterInfo.td" +//===----------------------------------------------------------------------===// +// Calling Convention Description +//===----------------------------------------------------------------------===// + +include "XtensaCallingConv.td" + //===----------------------------------------------------------------------===// // Instruction Descriptions //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/Xtensa/XtensaCallingConv.td b/llvm/lib/Target/Xtensa/XtensaCallingConv.td new file mode 100644 index 0000000000000..7da3eb6dd6585 --- /dev/null +++ b/llvm/lib/Target/Xtensa/XtensaCallingConv.td @@ -0,0 +1,27 @@ +//===- XtensaCallingConv.td - Xtensa Calling Conventions -*- tablegen ---*-===// +// +// 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 describes the calling conventions for the Xtensa ABI. +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Xtensa return value calling convention +//===----------------------------------------------------------------------===// +def RetCC_Xtensa : CallingConv<[ + CCIfType<[i1, i8, i16], CCPromoteToType>, + CCIfType<[f32], CCBitConvertToType>, + + // First two return values go in a2, a3, a4, a5 + CCIfType<[i32], CCAssignToReg<[A2, A3, A4, A5]>>, + CCIfType<[i64], CCAssignToRegWithShadow<[A2, A4], [A3, A5]>> +]>; + +//===----------------------------------------------------------------------===// +// Callee-saved register lists. +//===----------------------------------------------------------------------===// + +def CSR_Xtensa : CalleeSavedRegs<(add A0, A12, A13, A14, A15)>; diff --git a/llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp b/llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp index 3007372754522..5ebedefafc165 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp +++ b/llvm/lib/Target/Xtensa/XtensaISelDAGToDAG.cpp @@ -12,9 +12,11 @@ #include "Xtensa.h" #include "XtensaTargetMachine.h" +#include "XtensaUtils.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/SelectionDAGISel.h" +#include "llvm/IR/DiagnosticInfo.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" @@ -37,9 +39,57 @@ class XtensaDAGToDAGISel : public SelectionDAGISel { void Select(SDNode *Node) override; + // For load/store instructions generate (base+offset) pair from + // memory address. The offset must be a multiple of scale argument. bool selectMemRegAddr(SDValue Addr, SDValue &Base, SDValue &Offset, int Scale) { - report_fatal_error("MemReg address is not implemented yet"); + EVT ValTy = Addr.getValueType(); + + // if Address is FI, get the TargetFrameIndex. + if (FrameIndexSDNode *FIN = dyn_cast(Addr)) { + Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), ValTy); + Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), ValTy); + + return true; + } + + if (TM.isPositionIndependent()) { + DiagnosticInfoUnsupported Diag(CurDAG->getMachineFunction().getFunction(), + "PIC relocations are not supported ", + Addr.getDebugLoc()); + CurDAG->getContext()->diagnose(Diag); + } + + if ((Addr.getOpcode() == ISD::TargetExternalSymbol || + Addr.getOpcode() == ISD::TargetGlobalAddress)) + return false; + + // Addresses of the form FI+const + bool Valid = false; + if (CurDAG->isBaseWithConstantOffset(Addr)) { + ConstantSDNode *CN = dyn_cast(Addr.getOperand(1)); + int64_t OffsetVal = CN->getSExtValue(); + + Valid = isValidAddrOffset(Scale, OffsetVal); + + if (Valid) { + // If the first operand is a FI, get the TargetFI Node + if (FrameIndexSDNode *FIN = + dyn_cast(Addr.getOperand(0))) + Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), ValTy); + else + Base = Addr.getOperand(0); + + Offset = + CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(Addr), ValTy); + return true; + } + } + + // Last case + Base = Addr; + Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), Addr.getValueType()); + return true; } bool selectMemRegAddrISH1(SDValue Addr, SDValue &Base, SDValue &Offset) { diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp index 276fab838d17c..2179534a98082 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp @@ -41,10 +41,274 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &TM, setMinFunctionAlignment(Align(4)); + setBooleanContents(ZeroOrOneBooleanContent); + + // 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); + } + // Compute derived properties from the register classes computeRegisterProperties(STI.getRegisterInfo()); } +//===----------------------------------------------------------------------===// +// 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 || ValVT == MVT::f32) { + 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; +} + +// Value is a value of type VA.getValVT() that we need to copy into +// the location described by VA. Return a copy of Value converted to +// VA.getValVT(). The caller is responsible for handling indirect values. +static SDValue convertValVTToLocVT(SelectionDAG &DAG, SDLoc DL, CCValAssign &VA, + SDValue Value) { + switch (VA.getLocInfo()) { + case CCValAssign::SExt: + return DAG.getNode(ISD::SIGN_EXTEND, DL, VA.getLocVT(), Value); + case CCValAssign::ZExt: + return DAG.getNode(ISD::ZERO_EXTEND, DL, VA.getLocVT(), Value); + case CCValAssign::AExt: + return DAG.getNode(ISD::ANY_EXTEND, DL, VA.getLocVT(), Value); + case CCValAssign::BCvt: + return DAG.getNode(ISD::BITCAST, DL, VA.getLocVT(), Value); + case CCValAssign::Full: + return Value; + default: + report_fatal_error("Unhandled getLocInfo()"); + } +} + +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; +} + +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!"); + + // Promote the value as required. + RetValue = convertValVTToLocVT(DAG, DL, VA, RetValue); + + // 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); +} + SDValue XtensaTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const { switch (Op.getOpcode()) { @@ -54,5 +318,9 @@ SDValue XtensaTargetLowering::LowerOperation(SDValue Op, } const char *XtensaTargetLowering::getTargetNodeName(unsigned Opcode) const { + switch (Opcode) { + case XtensaISD::RET: + return "XtensaISD::RET"; + } return nullptr; } diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.h b/llvm/lib/Target/Xtensa/XtensaISelLowering.h index 8b03712efc9bb..599d0b9441980 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.h +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.h @@ -19,6 +19,11 @@ #include "llvm/CodeGen/TargetLowering.h" namespace llvm { + +namespace XtensaISD { +enum { FIRST_NUMBER = ISD::BUILTIN_OP_END, RET }; +} + class XtensaSubtarget; class XtensaTargetLowering : public TargetLowering { @@ -30,10 +35,28 @@ class XtensaTargetLowering : public TargetLowering { SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override; + SDValue LowerFormalArguments(SDValue Chain, CallingConv::ID CallConv, + bool isVarArg, + const SmallVectorImpl &Ins, + const SDLoc &DL, SelectionDAG &DAG, + SmallVectorImpl &InVals) const override; + + bool CanLowerReturn(CallingConv::ID CallConv, MachineFunction &MF, + bool isVarArg, + const SmallVectorImpl &Outs, + LLVMContext &Context) const override; + + SDValue LowerReturn(SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, + const SmallVectorImpl &Outs, + const SmallVectorImpl &OutVals, const SDLoc &DL, + SelectionDAG &DAG) const override; + const XtensaSubtarget &getSubtarget() const { return Subtarget; } private: const XtensaSubtarget &Subtarget; + + CCAssignFn *CCAssignFnForCall(CallingConv::ID CC, bool IsVarArg) const; }; } // end namespace llvm diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp b/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp index 41b794d64fdb1..20c27141f0df3 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp @@ -15,6 +15,7 @@ #include "XtensaInstrInfo.h" #include "XtensaTargetMachine.h" #include "llvm/CodeGen/MachineConstantPool.h" +#include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineRegisterInfo.h" @@ -23,5 +24,74 @@ using namespace llvm; +static inline const MachineInstrBuilder & +addFrameReference(const MachineInstrBuilder &MIB, int FI) { + MachineInstr *MI = MIB; + MachineFunction &MF = *MI->getParent()->getParent(); + MachineFrameInfo &MFFrame = MF.getFrameInfo(); + const MCInstrDesc &MCID = MI->getDesc(); + MachineMemOperand::Flags Flags = MachineMemOperand::MONone; + if (MCID.mayLoad()) + Flags |= MachineMemOperand::MOLoad; + if (MCID.mayStore()) + Flags |= MachineMemOperand::MOStore; + int64_t Offset = 0; + Align Alignment = MFFrame.getObjectAlign(FI); + + MachineMemOperand *MMO = + MF.getMachineMemOperand(MachinePointerInfo::getFixedStack(MF, FI, Offset), + Flags, MFFrame.getObjectSize(FI), Alignment); + return MIB.addFrameIndex(FI).addImm(Offset).addMemOperand(MMO); +} + XtensaInstrInfo::XtensaInstrInfo(const XtensaSubtarget &STI) : XtensaGenInstrInfo(), RI(STI), STI(STI) {} + +void XtensaInstrInfo::copyPhysReg(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + const DebugLoc &DL, MCRegister DestReg, + MCRegister SrcReg, bool KillSrc) const { + // The MOV instruction is not present in core ISA, + // so use OR instruction. + if (Xtensa::ARRegClass.contains(DestReg, SrcReg)) + BuildMI(MBB, MBBI, DL, get(Xtensa::OR), DestReg) + .addReg(SrcReg, getKillRegState(KillSrc)) + .addReg(SrcReg, getKillRegState(KillSrc)); + else + report_fatal_error("Impossible reg-to-reg copy"); +} + +void XtensaInstrInfo::storeRegToStackSlot( + MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, Register SrcReg, + bool isKill, int FrameIdx, const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI, Register VReg) const { + DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc(); + unsigned LoadOpcode, StoreOpcode; + getLoadStoreOpcodes(RC, LoadOpcode, StoreOpcode, FrameIdx); + MachineInstrBuilder MIB = BuildMI(MBB, MBBI, DL, get(StoreOpcode)) + .addReg(SrcReg, getKillRegState(isKill)); + addFrameReference(MIB, FrameIdx); +} + +void XtensaInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + Register DestReg, int FrameIdx, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI, + Register VReg) const { + DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc(); + unsigned LoadOpcode, StoreOpcode; + getLoadStoreOpcodes(RC, LoadOpcode, StoreOpcode, FrameIdx); + addFrameReference(BuildMI(MBB, MBBI, DL, get(LoadOpcode), DestReg), FrameIdx); +} + +void XtensaInstrInfo::getLoadStoreOpcodes(const TargetRegisterClass *RC, + unsigned &LoadOpcode, + unsigned &StoreOpcode, + int64_t offset) const { + assert((RC == &Xtensa::ARRegClass) && + "Unsupported regclass to load or store"); + + LoadOpcode = Xtensa::L32I; + StoreOpcode = Xtensa::S32I; +} diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.h b/llvm/lib/Target/Xtensa/XtensaInstrInfo.h index 8c73c9bd79408..efd62ff7fa16c 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.h +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.h @@ -38,6 +38,27 @@ class XtensaInstrInfo : public XtensaGenInstrInfo { // Return the XtensaRegisterInfo, which this class owns. const XtensaRegisterInfo &getRegisterInfo() const { return RI; } + void copyPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, + const DebugLoc &DL, MCRegister DestReg, MCRegister SrcReg, + bool KillSrc) const override; + + void storeRegToStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, Register SrcReg, + bool isKill, int FrameIndex, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI, + Register VReg) const override; + + void loadRegFromStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, Register DestReg, + int FrameIdx, const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI, + Register VReg) const override; + + // Get the load and store opcodes for a given register class and offset. + void getLoadStoreOpcodes(const TargetRegisterClass *RC, unsigned &LoadOpcode, + unsigned &StoreOpcode, int64_t offset) const; + const XtensaSubtarget &getSubtarget() const { return STI; } }; } // end namespace llvm diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td index 268a9943d8c16..cfdb0220ec663 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td @@ -14,6 +14,7 @@ include "XtensaInstrFormats.td" include "XtensaOperands.td" +include "XtensaOperators.td" //===----------------------------------------------------------------------===// // Arithmetic & Logical instructions @@ -238,6 +239,11 @@ def L32R : RI16_Inst<0x01, (outs AR:$t), (ins L32Rtarget:$label), let imm16 = label; } +//extending loads +def : Pat<(i32 (extloadi1 addr_ish1:$addr)), (L8UI addr_ish1:$addr)>; +def : Pat<(i32 (extloadi8 addr_ish1:$addr)), (L8UI addr_ish1:$addr)>; +def : Pat<(i32 (extloadi16 addr_ish2:$addr)), (L16UI addr_ish2:$addr)>; + //===----------------------------------------------------------------------===// // Conditional branch instructions //===----------------------------------------------------------------------===// @@ -426,7 +432,7 @@ let isReturn = 1, isTerminator = 1, isBarrier = 1, Uses = [A0] in { def RET : CALLX_Inst<0x00, 0x00, 0x00, (outs), (ins), - "ret", []> { + "ret", [(Xtensa_ret)]> { let m = 0x2; let n = 0x0; let s = 0; diff --git a/llvm/lib/Target/Xtensa/XtensaOperators.td b/llvm/lib/Target/Xtensa/XtensaOperators.td new file mode 100644 index 0000000000000..ff82df2260b66 --- /dev/null +++ b/llvm/lib/Target/Xtensa/XtensaOperators.td @@ -0,0 +1,13 @@ +//===- XtensaOperators.td - Xtensa-specific operators ---------*- tblgen-*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Node definitions +//===----------------------------------------------------------------------===// +def Xtensa_ret: SDNode<"XtensaISD::RET", SDTNone, + [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>; diff --git a/llvm/lib/Target/Xtensa/XtensaRegisterInfo.cpp b/llvm/lib/Target/Xtensa/XtensaRegisterInfo.cpp index f749cc51f96a0..28a61b5d59c98 100644 --- a/llvm/lib/Target/Xtensa/XtensaRegisterInfo.cpp +++ b/llvm/lib/Target/Xtensa/XtensaRegisterInfo.cpp @@ -13,6 +13,9 @@ #include "XtensaRegisterInfo.h" #include "XtensaInstrInfo.h" #include "XtensaSubtarget.h" +#include "XtensaUtils.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/Support/Debug.h" @@ -31,15 +34,13 @@ XtensaRegisterInfo::XtensaRegisterInfo(const XtensaSubtarget &STI) const uint16_t * XtensaRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const { - // Calling convention is not implemented yet - return nullptr; + return CSR_Xtensa_SaveList; } const uint32_t * XtensaRegisterInfo::getCallPreservedMask(const MachineFunction &MF, CallingConv::ID) const { - // Calling convention is not implemented yet - return nullptr; + return CSR_Xtensa_RegMask; } BitVector XtensaRegisterInfo::getReservedRegs(const MachineFunction &MF) const { @@ -60,7 +61,35 @@ BitVector XtensaRegisterInfo::getReservedRegs(const MachineFunction &MF) const { bool XtensaRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, int SPAdj, unsigned FIOperandNum, RegScavenger *RS) const { - report_fatal_error("Eliminate frame index not supported yet"); + MachineInstr &MI = *II; + MachineFunction &MF = *MI.getParent()->getParent(); + int FrameIndex = MI.getOperand(FIOperandNum).getIndex(); + uint64_t stackSize = MF.getFrameInfo().getStackSize(); + int64_t spOffset = MF.getFrameInfo().getObjectOffset(FrameIndex); + unsigned FrameReg = Xtensa::SP; + + // Calculate final offset. + // - There is no need to change the offset if the frame object is one of the + // following: an outgoing argument, pointer to a dynamically allocated + // stack space or a $gp restore location, + // - If the frame object is any of the following, its offset must be adjusted + // by adding the size of the stack: + // incoming argument, callee-saved register location or local variable. + bool IsKill = false; + int64_t Offset = + SPOffset + (int64_t)StackSize + MI.getOperand(FIOperandNum + 1).getImm(); + + bool Valid = isValidAddrOffset(MI, Offset); + + // If MI is not a debug value, make sure Offset fits in the 16-bit immediate + // field. + if (!MI.isDebugValue() && !Valid) + report_fatal_error("Load immediate not supported yet"); + + MI.getOperand(FIOperandNum).ChangeToRegister(FrameReg, false, false, IsKill); + MI.getOperand(FIOperandNum + 1).ChangeToImmediate(Offset); + + return false; } Register XtensaRegisterInfo::getFrameRegister(const MachineFunction &MF) const { diff --git a/llvm/lib/Target/Xtensa/XtensaUtils.cpp b/llvm/lib/Target/Xtensa/XtensaUtils.cpp new file mode 100644 index 0000000000000..831b161d1249c --- /dev/null +++ b/llvm/lib/Target/Xtensa/XtensaUtils.cpp @@ -0,0 +1,57 @@ +//===--- XtensaUtils.cpp ---- Xtensa Utility Functions ----------*- C++ -*-===// +// +// 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 contains miscellaneous utility functions. +// +//===----------------------------------------------------------------------===// + +#include "XtensaUtils.h" + +namespace llvm { + +bool isValidAddrOffset(int Scale, int64_t OffsetVal) { + bool Valid = false; + + switch (Scale) { + case 1: + Valid = (OffsetVal >= 0 && OffsetVal <= 255); + break; + case 2: + Valid = (OffsetVal >= 0 && OffsetVal <= 510) && ((OffsetVal & 0x1) == 0); + break; + case 4: + Valid = (OffsetVal >= 0 && OffsetVal <= 1020) && ((OffsetVal & 0x3) == 0); + break; + default: + break; + } + return Valid; +} + +bool isValidAddrOffset(MachineInstr &MI, int64_t Offset) { + int Scale = 0; + + switch (MI.getOpcode()) { + case Xtensa::L8UI: + case Xtensa::S8I: + Scale = 1; + break; + case Xtensa::L16SI: + case Xtensa::L16UI: + case Xtensa::S16I: + Scale = 2; + break; + default: + // assume that MI is 32-bit load/store operation + Scale = 4; + break; + } + return isValidAddrOffset(Scale, Offset); +} + +} // namespace llvm diff --git a/llvm/lib/Target/Xtensa/XtensaUtils.h b/llvm/lib/Target/Xtensa/XtensaUtils.h new file mode 100644 index 0000000000000..2b0ac37a6971a --- /dev/null +++ b/llvm/lib/Target/Xtensa/XtensaUtils.h @@ -0,0 +1,27 @@ +//===--- XtensaUtils.h ---- Xtensa Utility Functions ------------*- C++ -*-===// +// +// 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 contains miscellaneous utility functions. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_XTENSA_XTENSAUTILS_H +#define LLVM_LIB_TARGET_XTENSA_XTENSAUTILS_H + +#include "XtensaInstrInfo.h" +#include "llvm/CodeGen/MachineInstr.h" + +namespace llvm { +// Check address offset for load/store instructions. +// The offset should be multiple of scale. +bool isValidAddrOffset(int Scale, int64_t OffsetVal); + +// Check address offset for load/store instructions. +bool isValidAddrOffset(MachineInstr &MI, int64_t Offset); +} // namespace llvm +#endif // LLVM_LIB_TARGET_XTENSA_XTENSAUTILS_H diff --git a/llvm/test/CodeGen/Xtensa/calling-conv.ll b/llvm/test/CodeGen/Xtensa/calling-conv.ll new file mode 100644 index 0000000000000..41ae4220145c2 --- /dev/null +++ b/llvm/test/CodeGen/Xtensa/calling-conv.ll @@ -0,0 +1,78 @@ +; RUN: llc -mtriple=xtensa -O1 -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=XTENSA + +; Check placement of first 6 arguments in registers and 7th argument on stack +define dso_local i32 @test1(i32 noundef %0, i32 noundef %1, i32 noundef %2, i32 noundef %3, i32 noundef %4, i32 noundef %5, ptr nocapture noundef readonly byval(i32) align 4 %6) { +; XTENSA-LABEL: @test1 +; XTENSA: add a8, a7, a2 +; XTENSA: l32i a9, a1, 0 +; XTENSA: add a2, a8, a9 +; XTENSA: ret + %8 = load i32, ptr %6, align 4 + %9 = add nsw i32 %5, %0 + %10 = add nsw i32 %9, %8 + ret i32 %10 +} + +; Check placement of second i64 argument in registers +define dso_local i32 @test2(i32 noundef %0, i64 noundef %1, i32 noundef %2) { +; XTENSA-LABEL: @test2 +; XTENSA: add a8, a6, a2 +; XTENSA: add a2, a8, a4 +; XTENSA: ret + %4 = trunc i64 %1 to i32 + %5 = add nsw i32 %2, %0 + %6 = add nsw i32 %5, %4 + ret i32 %6 +} + +; Check placement of first argument typeof i8 in register +define dso_local i32 @test3(i8 noundef signext %0, i64 noundef %1, i32 noundef %2) { +; XTENSA-LABEL: @test3 +; XTENSA: add a8, a2, a6 +; XTENSA: add a2, a8, a4 +; XTENSA: ret + %4 = trunc i64 %1 to i32 + %5 = sext i8 %0 to i32 + %6 = add nsw i32 %5, %2 + %7 = add nsw i32 %6, %4 + ret i32 %7 +} + +; Check placement of 4th argument typeof i64 on stack +define dso_local i32 @test4(i8 noundef signext %0, i64 noundef %1, i32 noundef %2, ptr nocapture noundef readonly byval(i64) align 8 %3) { +; XTENSA-LABEL: @test4 +; XTENSA: add a8, a2, a6 +; XTENSA: add a8, a8, a4 +; XTENSA: l32i a9, a1, 0 +; XTENSA: add a2, a8, a9 +; XTENSA: ret + %5 = load i64, ptr %3, align 8 + %6 = trunc i64 %1 to i32 + %7 = trunc i64 %5 to i32 + %8 = sext i8 %0 to i32 + %9 = add nsw i32 %8, %2 + %10 = add nsw i32 %9, %6 + %11 = add nsw i32 %10, %7 + ret i32 %11 +} + +; Check placement of 128 bit structure on registers +define dso_local i32 @test5([4 x i32] %0, i32 noundef %1) { +; XTENSA-LABEL: @test5 +; XTENSA: add a2, a2, a6 +; XTENSA: ret + %3 = extractvalue [4 x i32] %0, 0 + %4 = add nsw i32 %3, %1 + ret i32 %4 +} + +; Check placement of 128 bit structure on stack +define dso_local i32 @test6(i32 noundef %0, [4 x i32] %1) { +; XTENSA-LABEL: @test6 +; XTENSA: add a2, a3, a2 +; XTENSA: ret + %3 = extractvalue [4 x i32] %1, 0 + %4 = add nsw i32 %3, %0 + ret i32 %4 +} diff --git a/llvm/test/CodeGen/Xtensa/stack-access.ll b/llvm/test/CodeGen/Xtensa/stack-access.ll new file mode 100644 index 0000000000000..1590d24f228f2 --- /dev/null +++ b/llvm/test/CodeGen/Xtensa/stack-access.ll @@ -0,0 +1,35 @@ +; RUN: llc -mtriple=xtensa -O0 -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=XTENSA + +define i8 @loadi8(i8 %a) { +; XTENSA-LABEL: loadi8: +; XTENSA: s8i a2, a1, 3 +; XTENSA: l8ui a2, a1, 3 +; XTENSA: ret + %b = alloca i8, align 1 + store i8 %a, ptr %b, align 1 + %1 = load i8, ptr %b, align 1 + ret i8 %1 +} + +define i16 @loadi16(i16 %a) { +; XTENSA-LABEL: loadi16: +; XTENSA: s16i a2, a1, 2 +; XTENSA: l16ui a2, a1, 2 +; XTENSA: ret + %b = alloca i16, align 2 + store i16 %a, ptr %b, align 2 + %1 = load i16, ptr %b, align 2 + ret i16 %1 +} + +define i32 @loadi32(i32 %a) { +; XTENSA-LABEL: loadi32: +; XTENSA: s32i a2, a1, 0 +; XTENSA: l32i a2, a1, 0 +; XTENSA: ret + %b = alloca i32, align 4 + store i32 %a, ptr %b, align 4 + %1 = load i32, ptr %b, align 4 + ret i32 %1 +} From 4689ab3959c9095441f56e3f41eca62ad3ece3ca Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Fri, 8 Mar 2024 01:22:40 +0300 Subject: [PATCH 2/6] [Xtensa] Implement call lowering. Implement lowering call operations. Implement stack pseudo instructions ADJCALLSTACKDOWN, ADJCALLSTACKUP. Implement basic support of the ConstantPool, integer and symbols constants placement in literal section. --- .../Xtensa/AsmParser/XtensaAsmParser.cpp | 135 ++++++++- llvm/lib/Target/Xtensa/CMakeLists.txt | 1 + .../Target/Xtensa/MCTargetDesc/CMakeLists.txt | 1 + .../MCTargetDesc/XtensaMCTargetDesc.cpp | 26 +- .../MCTargetDesc/XtensaTargetStreamer.cpp | 87 ++++++ .../MCTargetDesc/XtensaTargetStreamer.h | 46 +++ llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp | 188 ++++++++++++ llvm/lib/Target/Xtensa/XtensaAsmPrinter.h | 13 + .../Target/Xtensa/XtensaConstantPoolValue.cpp | 208 +++++++++++++ .../Target/Xtensa/XtensaConstantPoolValue.h | 265 +++++++++++++++++ .../lib/Target/Xtensa/XtensaFrameLowering.cpp | 20 ++ llvm/lib/Target/Xtensa/XtensaFrameLowering.h | 4 + llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 275 ++++++++++++++++++ llvm/lib/Target/Xtensa/XtensaISelLowering.h | 23 +- llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp | 67 ++++- llvm/lib/Target/Xtensa/XtensaInstrInfo.h | 8 + llvm/lib/Target/Xtensa/XtensaInstrInfo.td | 47 +++ llvm/lib/Target/Xtensa/XtensaOperands.td | 2 +- llvm/lib/Target/Xtensa/XtensaOperators.td | 23 ++ llvm/lib/Target/Xtensa/XtensaRegisterInfo.cpp | 45 ++- llvm/lib/Target/Xtensa/XtensaUtils.cpp | 2 + llvm/test/CodeGen/Xtensa/call.ll | 49 ++++ llvm/test/CodeGen/Xtensa/constantpool.ll | 28 ++ llvm/test/MC/Xtensa/Core/invalid.s | 4 - llvm/test/MC/Xtensa/directive-literal.s | 42 +++ 25 files changed, 1594 insertions(+), 15 deletions(-) create mode 100644 llvm/lib/Target/Xtensa/MCTargetDesc/XtensaTargetStreamer.cpp create mode 100644 llvm/lib/Target/Xtensa/MCTargetDesc/XtensaTargetStreamer.h create mode 100644 llvm/lib/Target/Xtensa/XtensaConstantPoolValue.cpp create mode 100644 llvm/lib/Target/Xtensa/XtensaConstantPoolValue.h create mode 100644 llvm/test/CodeGen/Xtensa/call.ll create mode 100644 llvm/test/CodeGen/Xtensa/constantpool.ll create mode 100644 llvm/test/MC/Xtensa/directive-literal.s diff --git a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp index 3f808298527f8..9fd05ee96a929 100644 --- a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp +++ b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp @@ -8,7 +8,9 @@ // //===----------------------------------------------------------------------===// +#include "MCTargetDesc/XtensaMCExpr.h" #include "MCTargetDesc/XtensaMCTargetDesc.h" +#include "MCTargetDesc/XtensaTargetStreamer.h" #include "TargetInfo/XtensaTargetInfo.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringSwitch.h" @@ -22,6 +24,7 @@ #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/MCSymbol.h" #include "llvm/MC/TargetRegistry.h" #include "llvm/Support/Casting.h" @@ -35,6 +38,12 @@ class XtensaAsmParser : public MCTargetAsmParser { SMLoc getLoc() const { return getParser().getTok().getLoc(); } + XtensaTargetStreamer &getTargetStreamer() { + MCTargetStreamer &TS = *getParser().getStreamer().getTargetStreamer(); + return static_cast(TS); + } + + bool ParseDirective(AsmToken DirectiveID) override; bool parseRegister(MCRegister &Reg, SMLoc &StartLoc, SMLoc &EndLoc) override; bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name, SMLoc NameLoc, OperandVector &Operands) override; @@ -45,6 +54,9 @@ class XtensaAsmParser : public MCTargetAsmParser { unsigned validateTargetOperandClass(MCParsedAsmOperand &Op, unsigned Kind) override; + bool processInstruction(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, + const MCSubtargetInfo *STI); + // Auto-generated instruction matching functions #define GET_ASSEMBLER_HEADER #include "XtensaGenAsmMatcher.inc" @@ -62,6 +74,7 @@ class XtensaAsmParser : public MCTargetAsmParser { return ParseStatus::NoMatch; } ParseStatus parsePCRelTarget(OperandVector &Operands); + bool parseLiteralDirective(SMLoc L); public: enum XtensaMatchResultTy { @@ -148,7 +161,13 @@ struct XtensaOperand : public MCParsedAsmOperand { bool isImm12() const { return isImm(-2048, 2047); } - bool isImm12m() const { return isImm(-2048, 2047); } + // Convert MOVI to literal load, when immediate is not in range (-2048, 2047) + bool isImm12m() const { + if (Kind == Immediate) + return true; + + return false; + } bool isOffset4m32() const { return isImm(0, 60) && @@ -348,6 +367,67 @@ static SMLoc RefineErrorLoc(const SMLoc Loc, const OperandVector &Operands, return Loc; } +bool XtensaAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, + MCStreamer &Out, + const MCSubtargetInfo *STI) { + Inst.setLoc(IDLoc); + const unsigned Opcode = Inst.getOpcode(); + switch (Opcode) { + case Xtensa::L32R: { + const MCSymbolRefExpr *OpExpr = + (const MCSymbolRefExpr *)Inst.getOperand(1).getExpr(); + XtensaMCExpr::VariantKind Kind = XtensaMCExpr::VK_Xtensa_None; + const MCExpr *NewOpExpr = XtensaMCExpr::create(OpExpr, Kind, getContext()); + Inst.getOperand(1).setExpr(NewOpExpr); + } break; + case Xtensa::MOVI: { + XtensaTargetStreamer &TS = this->getTargetStreamer(); + + // Expand MOVI operand + if (!Inst.getOperand(1).isExpr()) { + uint64_t ImmOp64 = Inst.getOperand(1).getImm(); + int32_t Imm = ImmOp64; + if ((Imm < -2048) || (Imm > 2047)) { + XtensaTargetStreamer &TS = this->getTargetStreamer(); + MCInst TmpInst; + TmpInst.setLoc(IDLoc); + TmpInst.setOpcode(Xtensa::L32R); + const MCExpr *Value = MCConstantExpr::create(ImmOp64, getContext()); + MCSymbol *Sym = getContext().createTempSymbol(); + const MCExpr *Expr = MCSymbolRefExpr::create( + Sym, MCSymbolRefExpr::VK_None, getContext()); + const MCExpr *OpExpr = XtensaMCExpr::create( + Expr, XtensaMCExpr::VK_Xtensa_None, getContext()); + TmpInst.addOperand(Inst.getOperand(0)); + MCOperand Op1 = MCOperand::createExpr(OpExpr); + TmpInst.addOperand(Op1); + TS.emitLiteral(Sym, Value, IDLoc); + Inst = TmpInst; + } + } else { + MCInst TmpInst; + TmpInst.setLoc(IDLoc); + TmpInst.setOpcode(Xtensa::L32R); + const MCExpr *Value = Inst.getOperand(1).getExpr(); + MCSymbol *Sym = getContext().createTempSymbol(); + const MCExpr *Expr = + MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext()); + const MCExpr *OpExpr = XtensaMCExpr::create( + Expr, XtensaMCExpr::VK_Xtensa_None, getContext()); + TmpInst.addOperand(Inst.getOperand(0)); + MCOperand Op1 = MCOperand::createExpr(OpExpr); + TmpInst.addOperand(Op1); + Inst = TmpInst; + TS.emitLiteral(Sym, Value, IDLoc); + } + } break; + default: + break; + } + + return true; +} + bool XtensaAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, OperandVector &Operands, MCStreamer &Out, @@ -361,6 +441,7 @@ bool XtensaAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, default: break; case Match_Success: + processInstruction(Inst, IDLoc, Out, STI); Inst.setLoc(IDLoc); Out.emitInstruction(Inst, getSTI()); return false; @@ -686,6 +767,58 @@ bool XtensaAsmParser::ParseInstruction(ParseInstructionInfo &Info, return false; } +bool XtensaAsmParser::parseLiteralDirective(SMLoc L) { + MCAsmParser &Parser = getParser(); + MCSymbol *Sym; + const MCExpr *Value; + SMLoc LiteralLoc = getLexer().getLoc(); + XtensaTargetStreamer &TS = this->getTargetStreamer(); + + if (Parser.parseExpression(Value)) + return true; + + const MCSymbolRefExpr *SE = dyn_cast(Value); + if (!SE) + return Error(LiteralLoc, "literal label must be a symbol"); + else { + Sym = getContext().getOrCreateSymbol(SE->getSymbol().getName()); + } + + if (Parser.parseToken(AsmToken::Comma, "expected comma")) + return true; + + SMLoc OpcodeLoc = getLexer().getLoc(); + if (parseOptionalToken(AsmToken::EndOfStatement)) + return Error(OpcodeLoc, "expected value"); + + if (Parser.parseExpression(Value)) + return true; + + TS.emitLiteral(Sym, Value, LiteralLoc); + + return false; +} + +bool XtensaAsmParser::ParseDirective(AsmToken DirectiveID) { + StringRef IDVal = DirectiveID.getString(); + SMLoc Loc = getLexer().getLoc(); + + if (IDVal == ".literal_position") { + XtensaTargetStreamer &TS = this->getTargetStreamer(); + TS.emitLiteralPosition(); + Lex(); + return false; + } + + if (IDVal == ".literal") { + parseLiteralDirective(Loc); + Lex(); + return false; + } + + return true; +} + // Force static initialization. extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeXtensaAsmParser() { RegisterMCAsmParser X(getTheXtensaTarget()); diff --git a/llvm/lib/Target/Xtensa/CMakeLists.txt b/llvm/lib/Target/Xtensa/CMakeLists.txt index 432b76d4fd576..726efadc87c0b 100644 --- a/llvm/lib/Target/Xtensa/CMakeLists.txt +++ b/llvm/lib/Target/Xtensa/CMakeLists.txt @@ -16,6 +16,7 @@ add_public_tablegen_target(XtensaCommonTableGen) add_llvm_target(XtensaCodeGen XtensaAsmPrinter.cpp + XtensaConstantPoolValue.cpp XtensaFrameLowering.cpp XtensaInstrInfo.cpp XtensaISelDAGToDAG.cpp diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/CMakeLists.txt b/llvm/lib/Target/Xtensa/MCTargetDesc/CMakeLists.txt index 6841b44f9d569..dc12863394c7a 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/CMakeLists.txt +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/CMakeLists.txt @@ -6,6 +6,7 @@ add_llvm_component_library(LLVMXtensaDesc XtensaMCCodeEmitter.cpp XtensaMCExpr.cpp XtensaMCTargetDesc.cpp + XtensaTargetStreamer.cpp LINK_COMPONENTS MC diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp index 48674d15bdfbe..8914ebf658cc4 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp @@ -10,6 +10,7 @@ #include "XtensaMCTargetDesc.h" #include "XtensaInstPrinter.h" #include "XtensaMCAsmInfo.h" +#include "XtensaTargetStreamer.h" #include "TargetInfo/XtensaTargetInfo.h" #include "llvm/ADT/STLExtras.h" #include "llvm/MC/MCAsmInfo.h" @@ -63,16 +64,29 @@ createXtensaMCSubtargetInfo(const Triple &TT, StringRef CPU, StringRef FS) { return createXtensaMCSubtargetInfoImpl(TT, CPU, CPU, FS); } +static MCTargetStreamer * +createXtensaAsmTargetStreamer(MCStreamer &S, formatted_raw_ostream &OS, + MCInstPrinter *InstPrint, bool isVerboseAsm) { + return new XtensaTargetAsmStreamer(S, OS); +} + +static MCTargetStreamer * +createXtensaObjectTargetStreamer(MCStreamer &S, const MCSubtargetInfo &STI) { + return new XtensaTargetELFStreamer(S); +} + extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeXtensaTargetMC() { // Register the MCAsmInfo. - TargetRegistry::RegisterMCAsmInfo(getTheXtensaTarget(), createXtensaMCAsmInfo); + TargetRegistry::RegisterMCAsmInfo(getTheXtensaTarget(), + createXtensaMCAsmInfo); // Register the MCCodeEmitter. TargetRegistry::RegisterMCCodeEmitter(getTheXtensaTarget(), createXtensaMCCodeEmitter); // Register the MCInstrInfo. - TargetRegistry::RegisterMCInstrInfo(getTheXtensaTarget(), createXtensaMCInstrInfo); + TargetRegistry::RegisterMCInstrInfo(getTheXtensaTarget(), + createXtensaMCInstrInfo); // Register the MCInstPrinter. TargetRegistry::RegisterMCInstPrinter(getTheXtensaTarget(), @@ -89,4 +103,12 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeXtensaTargetMC() { // Register the MCAsmBackend. TargetRegistry::RegisterMCAsmBackend(getTheXtensaTarget(), createXtensaMCAsmBackend); + + // Register the asm target streamer. + TargetRegistry::RegisterAsmTargetStreamer(getTheXtensaTarget(), + createXtensaAsmTargetStreamer); + + // Register the ELF target streamer. + TargetRegistry::RegisterObjectTargetStreamer( + getTheXtensaTarget(), createXtensaObjectTargetStreamer); } diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaTargetStreamer.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaTargetStreamer.cpp new file mode 100644 index 0000000000000..4163e64de48f0 --- /dev/null +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaTargetStreamer.cpp @@ -0,0 +1,87 @@ +//===-- XtensaTargetStreamer.cpp - Xtensa Target Streamer Methods ---------===// +// +// The LLVM Compiler Infrastructure +// +// 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 provides Xtensa specific target streamer methods. +// +//===----------------------------------------------------------------------===// + +#include "XtensaTargetStreamer.h" +#include "XtensaInstPrinter.h" +#include "llvm/BinaryFormat/ELF.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCObjectFileInfo.h" +#include "llvm/MC/MCSectionELF.h" +#include "llvm/Support/FormattedStream.h" + +using namespace llvm; + +XtensaTargetStreamer::XtensaTargetStreamer(MCStreamer &S) + : MCTargetStreamer(S) {} + +XtensaTargetAsmStreamer::XtensaTargetAsmStreamer(MCStreamer &S, + formatted_raw_ostream &OS) + : XtensaTargetStreamer(S), OS(OS) {} + +void XtensaTargetAsmStreamer::emitLiteral(MCSymbol *LblSym, const MCExpr *Value, + SMLoc L) { + const MCAsmInfo *MAI = Streamer.getContext().getAsmInfo(); + + OS << "\t.literal\t"; + LblSym->print(OS, MAI); + OS << ", "; + Value->print(OS, MAI); + OS << '\n'; +} + +void XtensaTargetAsmStreamer::emitLiteralPosition() { + OS << "\t.literal_position\n"; +} + +XtensaTargetELFStreamer::XtensaTargetELFStreamer(MCStreamer &S) + : XtensaTargetStreamer(S) {} + +static std::string getLiteralSectionName(std::string CSectionName) { + std::size_t Pos = CSectionName.find(".text"); + std::string SectionName; + if (Pos != std::string::npos) { + if (Pos > 0) + SectionName = CSectionName.substr(0, Pos + 5); + else + SectionName = ""; + SectionName += ".literal"; + SectionName += CSectionName.substr(Pos + 5); + } else { + SectionName = CSectionName; + SectionName += ".literal"; + } + return SectionName; +} + +void XtensaTargetELFStreamer::emitLiteral(MCSymbol *LblSym, const MCExpr *Value, + SMLoc L) { + MCContext &Context = getStreamer().getContext(); + MCStreamer &OutStreamer = getStreamer(); + MCSectionELF *CS = (MCSectionELF *)OutStreamer.getCurrentSectionOnly(); + std::string SectionName = getLiteralSectionName(CS->getName().str()); + + MCSection *ConstSection = Context.getELFSection( + SectionName, ELF::SHT_PROGBITS, ELF::SHF_EXECINSTR | ELF::SHF_ALLOC); + + OutStreamer.pushSection(); + OutStreamer.switchSection(ConstSection); + OutStreamer.emitLabel(LblSym, L); + OutStreamer.emitValue(Value, 4, L); + OutStreamer.popSection(); +} + +MCELFStreamer &XtensaTargetELFStreamer::getStreamer() { + return static_cast(Streamer); +} diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaTargetStreamer.h b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaTargetStreamer.h new file mode 100644 index 0000000000000..a7d8b6dd9c792 --- /dev/null +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaTargetStreamer.h @@ -0,0 +1,46 @@ +//===-- XtensaTargetStreamer.h - Xtensa Target Streamer --------*- C++ -*--===// +// +// The LLVM Compiler Infrastructure +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_XTENSA_XTENSATARGETSTREAMER_H +#define LLVM_LIB_TARGET_XTENSA_XTENSATARGETSTREAMER_H + +#include "llvm/MC/MCELFStreamer.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/Support/SMLoc.h" + +namespace llvm { +class formatted_raw_ostream; + +class XtensaTargetStreamer : public MCTargetStreamer { +public: + XtensaTargetStreamer(MCStreamer &S); + virtual void emitLiteral(MCSymbol *LblSym, const MCExpr *Value, SMLoc L) = 0; + virtual void emitLiteralPosition() = 0; +}; + +class XtensaTargetAsmStreamer : public XtensaTargetStreamer { + formatted_raw_ostream &OS; + +public: + XtensaTargetAsmStreamer(MCStreamer &S, formatted_raw_ostream &OS); + void emitLiteral(MCSymbol *LblSym, const MCExpr *Value, SMLoc L) override; + void emitLiteralPosition() override; +}; + +class XtensaTargetELFStreamer : public XtensaTargetStreamer { +public: + XtensaTargetELFStreamer(MCStreamer &S); + MCELFStreamer &getStreamer(); + void emitLiteral(MCSymbol *LblSym, const MCExpr *Value, SMLoc L) override; + void emitLiteralPosition() override {} +}; +} // end namespace llvm + +#endif diff --git a/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp b/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp index 87dbf2eb5166c..3c8977a742eae 100644 --- a/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp +++ b/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp @@ -12,8 +12,12 @@ //===----------------------------------------------------------------------===// #include "XtensaAsmPrinter.h" +#include "MCTargetDesc/XtensaMCExpr.h" #include "TargetInfo/XtensaTargetInfo.h" +#include "XtensaConstantPoolValue.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/BinaryFormat/ELF.h" +#include "llvm/CodeGen/MachineConstantPool.h" #include "llvm/CodeGen/MachineModuleInfoImpls.h" #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" #include "llvm/MC/MCExpr.h" @@ -25,12 +29,193 @@ using namespace llvm; +static MCSymbolRefExpr::VariantKind +getModifierVariantKind(XtensaCP::XtensaCPModifier Modifier) { + switch (Modifier) { + case XtensaCP::no_modifier: + return MCSymbolRefExpr::VK_None; + case XtensaCP::TPOFF: + return MCSymbolRefExpr::VK_TPOFF; + } + report_fatal_error("Invalid XtensaCPModifier!"); +} + void XtensaAsmPrinter::emitInstruction(const MachineInstr *MI) { MCInst LoweredMI; lowerToMCInst(MI, LoweredMI); EmitToStreamer(*OutStreamer, LoweredMI); } +void XtensaAsmPrinter::emitMachineConstantPoolValue( + MachineConstantPoolValue *MCPV) { + XtensaConstantPoolValue *ACPV = static_cast(MCPV); + MCSymbol *MCSym; + + assert(ACPV->isExtSymbol() && "unrecognized constant pool value"); + + XtensaConstantPoolSymbol *XtensaSym = cast(ACPV); + const char *Sym = XtensaSym->getSymbol(); + std::string SymName(Sym); + if (XtensaSym->isPrivateLinkage()) + SymName = ".L" + SymName; + MCSym = GetExternalSymbolSymbol(StringRef(SymName)); + + MCSymbol *LblSym = GetCPISymbol(ACPV->getLabelId()); + // TODO find a better way to check whether we emit data to .s file + if (OutStreamer->hasRawTextSupport()) { + std::string SymName("\t.literal "); + SymName += LblSym->getName(); + SymName += ", "; + SymName += MCSym->getName(); + + StringRef Modifier = ACPV->getModifierText(); + SymName += Modifier; + + OutStreamer->emitRawText(StringRef(SymName)); + } else { + MCSymbolRefExpr::VariantKind VK = + getModifierVariantKind(ACPV->getModifier()); + + if (ACPV->getModifier() != XtensaCP::no_modifier) { + std::string SymName(MCSym->getName()); + MCSym = GetExternalSymbolSymbol(StringRef(SymName)); + } + + const MCExpr *Expr = MCSymbolRefExpr::create(MCSym, VK, OutContext); + uint64_t Size = getDataLayout().getTypeAllocSize(ACPV->getType()); + OutStreamer->emitCodeAlignment( + Align(4), OutStreamer->getContext().getSubtargetInfo()); + OutStreamer->emitLabel(LblSym); + OutStreamer->emitValue(Expr, Size); + } +} + +void XtensaAsmPrinter::emitMachineConstantPoolEntry( + const MachineConstantPoolEntry &CPE, int i) { + if (CPE.isMachineConstantPoolEntry()) { + XtensaConstantPoolValue *ACPV = + static_cast(CPE.Val.MachineCPVal); + ACPV->setLabelId(i); + emitMachineConstantPoolValue(CPE.Val.MachineCPVal); + } else { + MCSymbol *LblSym = GetCPISymbol(i); + // TODO find a better way to check whether we emit data to .s file + if (OutStreamer->hasRawTextSupport()) { + std::string str("\t.literal "); + str += LblSym->getName(); + str += ", "; + const Constant *C = CPE.Val.ConstVal; + + if (const auto *CFP = dyn_cast(C)) { + str += toString(CFP->getValueAPF().bitcastToAPInt(), 10, true); + } else if (const auto *CI = dyn_cast(C)) { + str += toString(CI->getValue(), 10, true); + } else { + report_fatal_error( + "This constant type is not supported yet in constantpool"); + } + + OutStreamer->emitRawText(StringRef(str)); + } else { + OutStreamer->emitCodeAlignment( + Align(4), OutStreamer->getContext().getSubtargetInfo()); + OutStreamer->emitLabel(LblSym); + emitGlobalConstant(getDataLayout(), CPE.Val.ConstVal); + } + } +} + +// EmitConstantPool - Print to the current output stream assembly +// representations of the constants in the constant pool MCP. This is +// used to print out constants which have been "spilled to memory" by +// the code generator. +void XtensaAsmPrinter::emitConstantPool() { + const Function &F = MF->getFunction(); + const MachineConstantPool *MCP = MF->getConstantPool(); + const std::vector &CP = MCP->getConstants(); + if (CP.empty()) + return; + + for (unsigned i = 0, e = CP.size(); i != e; ++i) { + const MachineConstantPoolEntry &CPE = CP[i]; + + if (i == 0) { + if (OutStreamer->hasRawTextSupport()) { + OutStreamer->switchSection( + getObjFileLowering().SectionForGlobal(&F, TM)); + OutStreamer->emitRawText(StringRef("\t.literal_position\n")); + } else { + MCSectionELF *CS = + (MCSectionELF *)getObjFileLowering().SectionForGlobal(&F, TM); + std::string CSectionName = CS->getName().str(); + std::size_t Pos = CSectionName.find(".text"); + std::string SectionName; + if (Pos != std::string::npos) { + if (Pos > 0) + SectionName = CSectionName.substr(0, Pos + 5); + else + SectionName = ""; + SectionName += ".literal"; + SectionName += CSectionName.substr(Pos + 5); + } else { + SectionName = CSectionName; + SectionName += ".literal"; + } + + MCSectionELF *S = + OutContext.getELFSection(SectionName, ELF::SHT_PROGBITS, + ELF::SHF_EXECINSTR | ELF::SHF_ALLOC); + S->setAlignment(Align(4)); + OutStreamer->switchSection(S); + } + } + + emitMachineConstantPoolEntry(CPE, i); + } +} + +MCSymbol * +XtensaAsmPrinter::GetConstantPoolIndexSymbol(const MachineOperand &MO) const { + // Create a symbol for the name. + return GetCPISymbol(MO.getIndex()); +} + +MCOperand +XtensaAsmPrinter::LowerSymbolOperand(const MachineOperand &MO, + MachineOperand::MachineOperandType MOTy, + unsigned Offset) const { + const MCSymbol *Symbol; + XtensaMCExpr::VariantKind Kind = XtensaMCExpr::VK_Xtensa_None; + + switch (MOTy) { + case MachineOperand::MO_GlobalAddress: + Symbol = getSymbol(MO.getGlobal()); + Offset += MO.getOffset(); + break; + case MachineOperand::MO_ConstantPoolIndex: + Symbol = GetConstantPoolIndexSymbol(MO); + Offset += MO.getOffset(); + break; + default: + report_fatal_error(""); + } + + const MCExpr *ME = + MCSymbolRefExpr::create(Symbol, MCSymbolRefExpr::VK_None, OutContext); + ME = XtensaMCExpr::create(ME, Kind, OutContext); + + if (Offset) { + // Assume offset is never negative. + assert(Offset > 0); + + const MCConstantExpr *OffsetExpr = + MCConstantExpr::create(Offset, OutContext); + ME = MCBinaryExpr::createAdd(ME, OffsetExpr, OutContext); + } + + return MCOperand::createExpr(ME); +} + MCOperand XtensaAsmPrinter::lowerOperand(const MachineOperand &MO, unsigned Offset) const { MachineOperand::MachineOperandType MOTy = MO.getType(); @@ -45,6 +230,9 @@ MCOperand XtensaAsmPrinter::lowerOperand(const MachineOperand &MO, return MCOperand::createImm(MO.getImm() + Offset); case MachineOperand::MO_RegisterMask: break; + case MachineOperand::MO_GlobalAddress: + case MachineOperand::MO_ConstantPoolIndex: + return LowerSymbolOperand(MO, MOTy, Offset); default: report_fatal_error("unknown operand type"); } diff --git a/llvm/lib/Target/Xtensa/XtensaAsmPrinter.h b/llvm/lib/Target/Xtensa/XtensaAsmPrinter.h index dec2a1ee4954f..f3fec19724aab 100644 --- a/llvm/lib/Target/Xtensa/XtensaAsmPrinter.h +++ b/llvm/lib/Target/Xtensa/XtensaAsmPrinter.h @@ -15,6 +15,7 @@ #include "XtensaTargetMachine.h" #include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/MachineConstantPool.h" #include "llvm/Support/Compiler.h" namespace llvm { @@ -35,6 +36,18 @@ class LLVM_LIBRARY_VISIBILITY XtensaAsmPrinter : public AsmPrinter { StringRef getPassName() const override { return "Xtensa Assembly Printer"; } void emitInstruction(const MachineInstr *MI) override; + void emitConstantPool() override; + + void emitMachineConstantPoolEntry(const MachineConstantPoolEntry &CPE, int i); + + void emitMachineConstantPoolValue(MachineConstantPoolValue *MCPV) override; + + MCSymbol *GetConstantPoolIndexSymbol(const MachineOperand &MO) const; + + MCOperand LowerSymbolOperand(const MachineOperand &MO, + MachineOperand::MachineOperandType MOTy, + unsigned Offset) const; + // Lower MachineInstr MI to MCInst OutMI. void lowerToMCInst(const MachineInstr *MI, MCInst &OutMI) const; diff --git a/llvm/lib/Target/Xtensa/XtensaConstantPoolValue.cpp b/llvm/lib/Target/Xtensa/XtensaConstantPoolValue.cpp new file mode 100644 index 0000000000000..1cb1e577ae045 --- /dev/null +++ b/llvm/lib/Target/Xtensa/XtensaConstantPoolValue.cpp @@ -0,0 +1,208 @@ +//===- XtensaConstantPoolValue.cpp - Xtensa constantpool value ------------===// +// +// 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 implements the Xtensa specific constantpool value class. +// +//===----------------------------------------------------------------------===// + +#include "XtensaConstantPoolValue.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/CodeGen/MachineBasicBlock.h" +#include "llvm/IR/Constant.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/GlobalValue.h" +#include "llvm/IR/Type.h" +#include "llvm/Support/raw_ostream.h" +#include +using namespace llvm; + +XtensaConstantPoolValue::XtensaConstantPoolValue( + Type *Ty, unsigned id, XtensaCP::XtensaCPKind kind, + XtensaCP::XtensaCPModifier modifier) + : MachineConstantPoolValue(Ty), LabelId(id), Kind(kind), + Modifier(modifier) {} + +XtensaConstantPoolValue::XtensaConstantPoolValue( + LLVMContext &C, unsigned id, XtensaCP::XtensaCPKind kind, + XtensaCP::XtensaCPModifier modifier) + : MachineConstantPoolValue((Type *)Type::getInt32Ty(C)), LabelId(id), + Kind(kind), Modifier(modifier) {} + +XtensaConstantPoolValue::~XtensaConstantPoolValue() {} + +StringRef XtensaConstantPoolValue::getModifierText() const { + switch (Modifier) { + case XtensaCP::no_modifier: + return ""; + case XtensaCP::TPOFF: + return "@TPOFF"; + } + report_fatal_error("Unknown modifier!"); +} + +int XtensaConstantPoolValue::getExistingMachineCPValue(MachineConstantPool *CP, + Align Alignment) { + report_fatal_error("Shouldn't be calling this directly!"); +} + +void XtensaConstantPoolValue::addSelectionDAGCSEId(FoldingSetNodeID &ID) { + ID.AddInteger(LabelId); +} + +bool XtensaConstantPoolValue::hasSameValue(XtensaConstantPoolValue *ACPV) { + if (ACPV->Kind == Kind) { + if (ACPV->LabelId == LabelId) + return true; + } + return false; +} + +void XtensaConstantPoolValue::dump() const { errs() << " " << *this; } + +void XtensaConstantPoolValue::print(raw_ostream &O) const {} + +//===----------------------------------------------------------------------===// +// XtensaConstantPoolConstant +//===----------------------------------------------------------------------===// + +XtensaConstantPoolConstant::XtensaConstantPoolConstant( + const Constant *C, unsigned ID, XtensaCP::XtensaCPKind Kind) + : XtensaConstantPoolValue((Type *)C->getType(), ID, Kind), + CVal(C) {} + +XtensaConstantPoolConstant * +XtensaConstantPoolConstant::Create(const Constant *C, unsigned ID, + XtensaCP::XtensaCPKind Kind) { + return new XtensaConstantPoolConstant(C, ID, Kind); +} + +const BlockAddress *XtensaConstantPoolConstant::getBlockAddress() const { + return dyn_cast_or_null(CVal); +} + +int XtensaConstantPoolConstant::getExistingMachineCPValue( + MachineConstantPool *CP, Align Alignment) { + return getExistingMachineCPValueImpl(CP, + Alignment); +} + +bool XtensaConstantPoolConstant::hasSameValue(XtensaConstantPoolValue *ACPV) { + const XtensaConstantPoolConstant *ACPC = + dyn_cast(ACPV); + return ACPC && ACPC->CVal == CVal && + XtensaConstantPoolValue::hasSameValue(ACPV); +} + +void XtensaConstantPoolConstant::addSelectionDAGCSEId(FoldingSetNodeID &ID) { + ID.AddPointer(CVal); + XtensaConstantPoolValue::addSelectionDAGCSEId(ID); +} + +void XtensaConstantPoolConstant::print(raw_ostream &O) const { + O << CVal->getName(); + XtensaConstantPoolValue::print(O); +} + +XtensaConstantPoolSymbol::XtensaConstantPoolSymbol( + LLVMContext &C, const char *s, unsigned id, bool PrivLinkage, + XtensaCP::XtensaCPModifier Modifier) + : XtensaConstantPoolValue(C, id, XtensaCP::CPExtSymbol, Modifier), S(s), + PrivateLinkage(PrivLinkage) {} + +XtensaConstantPoolSymbol * +XtensaConstantPoolSymbol::Create(LLVMContext &C, const char *s, unsigned ID, + bool PrivLinkage, + XtensaCP::XtensaCPModifier Modifier) + +{ + return new XtensaConstantPoolSymbol(C, s, ID, PrivLinkage, Modifier); +} + +int XtensaConstantPoolSymbol::getExistingMachineCPValue(MachineConstantPool *CP, + Align Alignment) { + return getExistingMachineCPValueImpl(CP, Alignment); +} + +bool XtensaConstantPoolSymbol::hasSameValue(XtensaConstantPoolValue *ACPV) { + const XtensaConstantPoolSymbol *ACPS = + dyn_cast(ACPV); + return ACPS && ACPS->S == S && XtensaConstantPoolValue::hasSameValue(ACPV); +} + +void XtensaConstantPoolSymbol::addSelectionDAGCSEId(FoldingSetNodeID &ID) { + ID.AddString(S); + XtensaConstantPoolValue::addSelectionDAGCSEId(ID); +} + +void XtensaConstantPoolSymbol::print(raw_ostream &O) const { + O << S; + XtensaConstantPoolValue::print(O); +} + +XtensaConstantPoolMBB::XtensaConstantPoolMBB(LLVMContext &C, + const MachineBasicBlock *mbb, + unsigned id) + : XtensaConstantPoolValue(C, 0, XtensaCP::CPMachineBasicBlock), + MBB(mbb) {} + +XtensaConstantPoolMBB * +XtensaConstantPoolMBB::Create(LLVMContext &C, const MachineBasicBlock *mbb, + unsigned idx) { + return new XtensaConstantPoolMBB(C, mbb, idx); +} + +int XtensaConstantPoolMBB::getExistingMachineCPValue(MachineConstantPool *CP, + Align Alignment) { + return getExistingMachineCPValueImpl(CP, Alignment); +} + +bool XtensaConstantPoolMBB::hasSameValue(XtensaConstantPoolValue *ACPV) { + const XtensaConstantPoolMBB *ACPMBB = dyn_cast(ACPV); + return ACPMBB && ACPMBB->MBB == MBB && + XtensaConstantPoolValue::hasSameValue(ACPV); +} + +void XtensaConstantPoolMBB::addSelectionDAGCSEId(FoldingSetNodeID &ID) { + ID.AddPointer(MBB); + XtensaConstantPoolValue::addSelectionDAGCSEId(ID); +} + +void XtensaConstantPoolMBB::print(raw_ostream &O) const { + O << "BB#" << MBB->getNumber(); + XtensaConstantPoolValue::print(O); +} + +XtensaConstantPoolJumpTable::XtensaConstantPoolJumpTable(LLVMContext &C, + unsigned idx) + : XtensaConstantPoolValue(C, 0, XtensaCP::CPJumpTable), IDX(idx) {} + +XtensaConstantPoolJumpTable *XtensaConstantPoolJumpTable::Create(LLVMContext &C, + unsigned idx) { + return new XtensaConstantPoolJumpTable(C, idx); +} + +int XtensaConstantPoolJumpTable::getExistingMachineCPValue( + MachineConstantPool *CP, Align Alignment) { + return getExistingMachineCPValueImpl(CP, + Alignment); +} + +bool XtensaConstantPoolJumpTable::hasSameValue(XtensaConstantPoolValue *ACPV) { + const XtensaConstantPoolJumpTable *ACPJT = + dyn_cast(ACPV); + return ACPJT && ACPJT->IDX == IDX && + XtensaConstantPoolValue::hasSameValue(ACPV); +} + +void XtensaConstantPoolJumpTable::addSelectionDAGCSEId(FoldingSetNodeID &ID) {} + +void XtensaConstantPoolJumpTable::print(raw_ostream &O) const { + O << "JT" << IDX; + XtensaConstantPoolValue::print(O); +} + diff --git a/llvm/lib/Target/Xtensa/XtensaConstantPoolValue.h b/llvm/lib/Target/Xtensa/XtensaConstantPoolValue.h new file mode 100644 index 0000000000000..c92ee5fd5f0e7 --- /dev/null +++ b/llvm/lib/Target/Xtensa/XtensaConstantPoolValue.h @@ -0,0 +1,265 @@ +//===- XtensaConstantPoolValue.h - Xtensa constantpool value ----*- C++ -*-===// +// +// 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 implements the Xtensa specific constantpool value class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_XTENSA_XTENSACONSTANTPOOLVALUE_H +#define LLVM_LIB_TARGET_XTENSA_XTENSACONSTANTPOOLVALUE_H + +#include "llvm/CodeGen/MachineConstantPool.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/ErrorHandling.h" +#include +#include +#include + +namespace llvm { + +class BlockAddress; +class Constant; +class GlobalValue; +class LLVMContext; +class MachineBasicBlock; + +namespace XtensaCP { +enum XtensaCPKind { + CPExtSymbol, + CPBlockAddress, + CPMachineBasicBlock, + CPJumpTable +}; + +enum XtensaCPModifier { + no_modifier, // None + TPOFF // Thread Pointer Offset +}; +} // namespace XtensaCP + +/// XtensaConstantPoolValue - Xtensa specific constantpool value. This is used +/// to represent PC-relative displacement between the address of the load +/// instruction and the constant being loaded. +class XtensaConstantPoolValue : public MachineConstantPoolValue { + unsigned LabelId; // Label id of the load. + XtensaCP::XtensaCPKind Kind; // Kind of constant. + XtensaCP::XtensaCPModifier Modifier; // Symbol name modifier + //(for example Global Variable name) + +protected: + XtensaConstantPoolValue( + Type *Ty, unsigned id, XtensaCP::XtensaCPKind Kind, + XtensaCP::XtensaCPModifier Modifier = XtensaCP::no_modifier); + + XtensaConstantPoolValue( + LLVMContext &C, unsigned id, XtensaCP::XtensaCPKind Kind, + XtensaCP::XtensaCPModifier Modifier = XtensaCP::no_modifier); + + template + int getExistingMachineCPValueImpl(MachineConstantPool *CP, Align Alignment) { + const std::vector &Constants = CP->getConstants(); + for (unsigned i = 0, e = Constants.size(); i != e; ++i) { + if (Constants[i].isMachineConstantPoolEntry() && + (Constants[i].getAlign() >= Alignment)) { + XtensaConstantPoolValue *CPV = + (XtensaConstantPoolValue *)Constants[i].Val.MachineCPVal; + if (Derived *APC = dyn_cast(CPV)) + if (cast(this)->equals(APC)) + return i; + } + } + + return -1; + } + +public: + ~XtensaConstantPoolValue() override; + + XtensaCP::XtensaCPModifier getModifier() const { return Modifier; } + bool hasModifier() const { return Modifier != XtensaCP::no_modifier; } + StringRef getModifierText() const; + + unsigned getLabelId() const { return LabelId; } + void setLabelId(unsigned id) { LabelId = id; } + + bool isExtSymbol() const { return Kind == XtensaCP::CPExtSymbol; } + bool isBlockAddress() const { return Kind == XtensaCP::CPBlockAddress; } + bool isMachineBasicBlock() const { + return Kind == XtensaCP::CPMachineBasicBlock; + } + bool isJumpTable() const { return Kind == XtensaCP::CPJumpTable; } + + int getExistingMachineCPValue(MachineConstantPool *CP, + Align Alignment) override; + + void addSelectionDAGCSEId(FoldingSetNodeID &ID) override; + + /// hasSameValue - Return true if this Xtensa constpool value can share the + /// same constantpool entry as another Xtensa constpool value. + virtual bool hasSameValue(XtensaConstantPoolValue *ACPV); + + bool equals(const XtensaConstantPoolValue *A) const { + return this->LabelId == A->LabelId && this->Modifier == A->Modifier; + } + + void print(raw_ostream &O) const override; + void print(raw_ostream *O) const { + if (O) + print(*O); + } + void dump() const; +}; + +inline raw_ostream &operator<<(raw_ostream &O, + const XtensaConstantPoolValue &V) { + V.print(O); + return O; +} + +/// XtensaConstantPoolConstant - Xtensa-specific constant pool values for +/// Constants (for example BlockAddresses). +class XtensaConstantPoolConstant : public XtensaConstantPoolValue { + const Constant *CVal; // Constant being loaded. + + XtensaConstantPoolConstant(const Constant *C, unsigned ID, + XtensaCP::XtensaCPKind Kind); + +public: + static XtensaConstantPoolConstant *Create(const Constant *C, unsigned ID, + XtensaCP::XtensaCPKind Kind); + + const BlockAddress *getBlockAddress() const; + + int getExistingMachineCPValue(MachineConstantPool *CP, + Align Alignment) override; + + /// hasSameValue - Return true if this Xtensa constpool value can share the + /// same constantpool entry as another Xtensa constpool value. + bool hasSameValue(XtensaConstantPoolValue *ACPV) override; + + void addSelectionDAGCSEId(FoldingSetNodeID &ID) override; + + void print(raw_ostream &O) const override; + static bool classof(const XtensaConstantPoolValue *APV) { + return APV->isBlockAddress(); + } + + bool equals(const XtensaConstantPoolConstant *A) const { + return CVal == A->CVal && XtensaConstantPoolValue::equals(A); + } +}; + + +/// XtensaConstantPoolSymbol - Xtensa-specific constantpool values for external +/// symbols. +class XtensaConstantPoolSymbol : public XtensaConstantPoolValue { + const std::string S; // ExtSymbol being loaded. + bool PrivateLinkage; + + XtensaConstantPoolSymbol( + LLVMContext &C, const char *s, unsigned id, bool PrivLinkage, + XtensaCP::XtensaCPModifier Modifier = XtensaCP::no_modifier); + +public: + static XtensaConstantPoolSymbol * + Create(LLVMContext &C, const char *s, unsigned ID, bool PrivLinkage, + XtensaCP::XtensaCPModifier Modifier = XtensaCP::no_modifier); + + const char *getSymbol() const { return S.c_str(); } + + int getExistingMachineCPValue(MachineConstantPool *CP, + Align Alignment) override; + + void addSelectionDAGCSEId(FoldingSetNodeID &ID) override; + + /// hasSameValue - Return true if this Xtensa constpool value can share the + /// same constantpool entry as another Xtensa constpool value. + bool hasSameValue(XtensaConstantPoolValue *ACPV) override; + + bool isPrivateLinkage() { return PrivateLinkage; } + + void print(raw_ostream &O) const override; + + static bool classof(const XtensaConstantPoolValue *ACPV) { + return ACPV->isExtSymbol(); + } + + bool equals(const XtensaConstantPoolSymbol *A) const { + return S == A->S && XtensaConstantPoolValue::equals(A); + } +}; + +/// XtensaConstantPoolMBB - Xtensa-specific constantpool value of a machine +/// basic block. +class XtensaConstantPoolMBB : public XtensaConstantPoolValue { + const MachineBasicBlock *MBB; // Machine basic block. + + XtensaConstantPoolMBB(LLVMContext &C, const MachineBasicBlock *mbb, + unsigned id); + +public: + static XtensaConstantPoolMBB * + Create(LLVMContext &C, const MachineBasicBlock *mbb, unsigned ID); + + const MachineBasicBlock *getMBB() const { return MBB; } + + int getExistingMachineCPValue(MachineConstantPool *CP, + Align Alignment) override; + + void addSelectionDAGCSEId(FoldingSetNodeID &ID) override; + + /// hasSameValue - Return true if this Xtensa constpool value can share the + /// same constantpool entry as another Xtensa constpool value. + bool hasSameValue(XtensaConstantPoolValue *ACPV) override; + + void print(raw_ostream &O) const override; + + static bool classof(const XtensaConstantPoolValue *ACPV) { + return ACPV->isMachineBasicBlock(); + } + + bool equals(const XtensaConstantPoolMBB *A) const { + return MBB == A->MBB && XtensaConstantPoolValue::equals(A); + } +}; + +/// XtensaConstantPoolJumpTable - Xtensa-specific constantpool values for Jump +/// Table symbols. +class XtensaConstantPoolJumpTable : public XtensaConstantPoolValue { + unsigned IDX; // Jump Table Index. + + XtensaConstantPoolJumpTable(LLVMContext &C, unsigned idx); + +public: + static XtensaConstantPoolJumpTable *Create(LLVMContext &C, unsigned idx); + + unsigned getIndex() const { return IDX; } + + int getExistingMachineCPValue(MachineConstantPool *CP, + Align Alignment) override; + + void addSelectionDAGCSEId(FoldingSetNodeID &ID) override; + + /// hasSameValue - Return true if this Xtensa constpool value can share the + /// same constantpool entry as another Xtensa constpool value. + bool hasSameValue(XtensaConstantPoolValue *ACPV) override; + + void print(raw_ostream &O) const override; + + static bool classof(const XtensaConstantPoolValue *ACPV) { + return ACPV->isJumpTable(); + } + + bool equals(const XtensaConstantPoolJumpTable *A) const { + return IDX == A->IDX && XtensaConstantPoolValue::equals(A); + } +}; + +} // namespace llvm + +#endif /* LLVM_LIB_TARGET_XTENSA_XTENSACONSTANTPOOLVALUE_H */ diff --git a/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp b/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp index 2092a2d947f86..ab37c09bf8bfe 100644 --- a/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp @@ -37,3 +37,23 @@ void XtensaFrameLowering::emitPrologue(MachineFunction &MF, void XtensaFrameLowering::emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const {} + +// Eliminate ADJCALLSTACKDOWN, ADJCALLSTACKUP pseudo instructions +MachineBasicBlock::iterator XtensaFrameLowering::eliminateCallFramePseudoInstr( + MachineFunction &MF, MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const { + const XtensaInstrInfo &TII = + *static_cast(MF.getSubtarget().getInstrInfo()); + + if (!hasReservedCallFrame(MF)) { + int64_t Amount = I->getOperand(0).getImm(); + + if (I->getOpcode() == Xtensa::ADJCALLSTACKDOWN) + Amount = -Amount; + + unsigned SP = Xtensa::SP; + TII.adjustStackPtr(SP, Amount, MBB, I); + } + + return MBB.erase(I); +} diff --git a/llvm/lib/Target/Xtensa/XtensaFrameLowering.h b/llvm/lib/Target/Xtensa/XtensaFrameLowering.h index 19e52310a99d9..2da88ab14073a 100644 --- a/llvm/lib/Target/Xtensa/XtensaFrameLowering.h +++ b/llvm/lib/Target/Xtensa/XtensaFrameLowering.h @@ -25,6 +25,10 @@ class XtensaFrameLowering : public TargetFrameLowering { /// the function. void emitPrologue(MachineFunction &, MachineBasicBlock &) const override; void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const override; + + MachineBasicBlock::iterator + eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const override; }; } // namespace llvm diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp index 2179534a98082..ee0618d577a07 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp @@ -11,6 +11,7 @@ // //===----------------------------------------------------------------------===// +#include "XtensaConstantPoolValue.h" #include "XtensaISelLowering.h" #include "XtensaSubtarget.h" #include "XtensaTargetMachine.h" @@ -23,14 +24,24 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.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); @@ -41,6 +52,9 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &TM, setMinFunctionAlignment(Align(4)); + setOperationAction(ISD::Constant, MVT::i32, Custom); + setOperationAction(ISD::Constant, MVT::i64, Expand); + setBooleanContents(ZeroOrOneBooleanContent); // No sign extend instructions for i1 @@ -50,6 +64,8 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &TM, setLoadExtAction(ISD::EXTLOAD, VT, MVT::i1, Promote); } + setOperationAction(ISD::ConstantPool, PtrVT, Custom); + // Compute derived properties from the register classes computeRegisterProperties(STI.getRegisterInfo()); } @@ -141,6 +157,32 @@ CCAssignFn *XtensaTargetLowering::CCAssignFnForCall(CallingConv::ID CC, return CC_Xtensa_Custom; } +// Value is a value that has been passed to us in the location described by VA +// (and so has type VA.getLocVT()). Convert Value to VA.getValVT(), chaining +// any loads onto Chain. +static SDValue convertLocVTToValVT(SelectionDAG &DAG, const SDLoc &DL, + CCValAssign &VA, SDValue Chain, + SDValue Value) { + // If the argument has been promoted from a smaller type, insert an + // assertion to capture this. + if (VA.getLocInfo() == CCValAssign::SExt) + Value = DAG.getNode(ISD::AssertSext, DL, VA.getLocVT(), Value, + DAG.getValueType(VA.getValVT())); + else if (VA.getLocInfo() == CCValAssign::ZExt) + Value = DAG.getNode(ISD::AssertZext, DL, VA.getLocVT(), Value, + DAG.getValueType(VA.getValVT())); + + if (VA.isExtInLoc()) + Value = DAG.getNode(ISD::TRUNCATE, DL, VA.getValVT(), Value); + else if (VA.getLocInfo() == CCValAssign::Indirect) + Value = DAG.getLoad(VA.getValVT(), DL, Chain, Value, MachinePointerInfo()); + else if (VA.getValVT() == MVT::f32) + Value = DAG.getNode(ISD::BITCAST, DL, VA.getValVT(), Value); + else + assert(VA.getLocInfo() == CCValAssign::Full && "Unsupported getLocInfo"); + return Value; +} + // Value is a value of type VA.getValVT() that we need to copy into // the location described by VA. Return a copy of Value converted to // VA.getValVT(). The caller is responsible for handling indirect values. @@ -252,6 +294,187 @@ SDValue XtensaTargetLowering::LowerFormalArguments( 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(); + + unsigned StackAlignment = TFL->getStackAlignment(); + 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; + + ArgValue = convertValVTToLocVT(DAG, DL, VA, ArgValue); + + 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, + /*isTailCall=*/false, 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); + + // Convert the value of the return register into the value that's + // being returned. + InVals.push_back(convertLocVTToValVT(DAG, DL, VA, Chain, RetValue)); + } + return Chain; +} + bool XtensaTargetLowering::CanLowerReturn( CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg, const SmallVectorImpl &Outs, LLVMContext &Context) const { @@ -309,9 +532,57 @@ XtensaTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv, return DAG.getNode(XtensaISD::RET, DL, MVT::Other, RetOps); } +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) && + (value >= -32768) && (value <= 32512) && ((value & 0xff) == 0)) + 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::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::LowerOperation(SDValue Op, SelectionDAG &DAG) const { switch (Op.getOpcode()) { + case ISD::Constant: + return LowerImmediate(Op, DAG); + case ISD::ConstantPool: + return LowerConstantPool(cast(Op), DAG); default: report_fatal_error("Unexpected node to lower"); } @@ -319,6 +590,10 @@ SDValue XtensaTargetLowering::LowerOperation(SDValue Op, const char *XtensaTargetLowering::getTargetNodeName(unsigned Opcode) const { switch (Opcode) { + case XtensaISD::CALL: + return "XtensaISD::CALL"; + case XtensaISD::PCREL_WRAPPER: + return "XtensaISD::PCREL_WRAPPER"; case XtensaISD::RET: return "XtensaISD::RET"; } diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.h b/llvm/lib/Target/Xtensa/XtensaISelLowering.h index 599d0b9441980..077559e2d6129 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.h +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.h @@ -21,7 +21,19 @@ namespace llvm { namespace XtensaISD { -enum { FIRST_NUMBER = ISD::BUILTIN_OP_END, RET }; +enum { + FIRST_NUMBER = ISD::BUILTIN_OP_END, + + // Calls a function. Operand 0 is the chain operand and operand 1 + // is the target address. The arguments start at operand 2. + // There is an optional glue operand at the end. + CALL, + + // Wraps a TargetGlobalAddress that should be loaded using PC-relative + // accesses. Operand 0 is the address. + PCREL_WRAPPER, + RET +}; } class XtensaSubtarget; @@ -41,6 +53,9 @@ class XtensaTargetLowering : public TargetLowering { const SDLoc &DL, SelectionDAG &DAG, SmallVectorImpl &InVals) const override; + SDValue LowerCall(CallLoweringInfo &CLI, + SmallVectorImpl &InVals) const override; + bool CanLowerReturn(CallingConv::ID CallConv, MachineFunction &MF, bool isVarArg, const SmallVectorImpl &Outs, @@ -56,6 +71,12 @@ class XtensaTargetLowering : public TargetLowering { private: const XtensaSubtarget &Subtarget; + SDValue LowerImmediate(SDValue Op, SelectionDAG &DAG) const; + + SDValue LowerConstantPool(ConstantPoolSDNode *CP, SelectionDAG &DAG) const; + + SDValue getAddrPCRel(SDValue Op, SelectionDAG &DAG) const; + CCAssignFn *CCAssignFnForCall(CallingConv::ID CC, bool IsVarArg) const; }; diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp b/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp index 20c27141f0df3..2c3d237c97296 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp @@ -45,7 +45,38 @@ addFrameReference(const MachineInstrBuilder &MIB, int FI) { } XtensaInstrInfo::XtensaInstrInfo(const XtensaSubtarget &STI) - : XtensaGenInstrInfo(), RI(STI), STI(STI) {} + : XtensaGenInstrInfo(Xtensa::ADJCALLSTACKDOWN, Xtensa::ADJCALLSTACKUP), + RI(STI), STI(STI) {} + +/// Adjust SP by Amount bytes. +void XtensaInstrInfo::adjustStackPtr(unsigned SP, int64_t Amount, + MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const { + DebugLoc DL = I != MBB.end() ? I->getDebugLoc() : DebugLoc(); + + if (Amount == 0) + return; + + MachineRegisterInfo &RegInfo = MBB.getParent()->getRegInfo(); + const TargetRegisterClass *RC = &Xtensa::ARRegClass; + + // create virtual reg to store immediate + unsigned Reg = RegInfo.createVirtualRegister(RC); + + if (isInt<8>(Amount)) // addi sp, sp, amount + BuildMI(MBB, I, DL, get(Xtensa::ADDI), Reg).addReg(SP).addImm(Amount); + else { // Expand immediate that doesn't fit in 12-bit. + unsigned Reg1; + loadImmediate(MBB, I, &Reg1, Amount); + BuildMI(MBB, I, DL, get(Xtensa::ADD), Reg) + .addReg(SP) + .addReg(Reg1, RegState::Kill); + } + + BuildMI(MBB, I, DL, get(Xtensa::OR), SP) + .addReg(Reg, RegState::Kill) + .addReg(Reg, RegState::Kill); +} void XtensaInstrInfo::copyPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, @@ -95,3 +126,37 @@ void XtensaInstrInfo::getLoadStoreOpcodes(const TargetRegisterClass *RC, LoadOpcode = Xtensa::L32I; StoreOpcode = Xtensa::S32I; } + +void XtensaInstrInfo::loadImmediate(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + unsigned *Reg, int64_t Value) const { + DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc(); + MachineRegisterInfo &RegInfo = MBB.getParent()->getRegInfo(); + const TargetRegisterClass *RC = &Xtensa::ARRegClass; + + // create virtual reg to store immediate + *Reg = RegInfo.createVirtualRegister(RC); + if (Value >= -2048 && Value <= 2047) { + BuildMI(MBB, MBBI, DL, get(Xtensa::MOVI), *Reg).addImm(Value); + } else if (Value >= -32768 && Value <= 32767) { + int Low = Value & 0xFF; + int High = Value & ~0xFF; + + BuildMI(MBB, MBBI, DL, get(Xtensa::MOVI), *Reg).addImm(Low); + BuildMI(MBB, MBBI, DL, get(Xtensa::ADDMI), *Reg).addReg(*Reg).addImm(High); + } else if (Value >= -4294967296LL && Value <= 4294967295LL) { + // 32 bit arbirary constant + MachineConstantPool *MCP = MBB.getParent()->getConstantPool(); + uint64_t UVal = ((uint64_t)Value) & 0xFFFFFFFFLL; + const Constant *CVal = ConstantInt::get( + Type::getInt32Ty(MBB.getParent()->getFunction().getContext()), UVal, + false); + unsigned Idx = MCP->getConstantPoolIndex(CVal, Align(2U)); + // MCSymbol MSym + BuildMI(MBB, MBBI, DL, get(Xtensa::L32R), *Reg).addConstantPoolIndex(Idx); + } else { + // use L32R to let assembler load immediate best + // TODO replace to L32R + report_fatal_error("Unsupported load immediate value"); + } +} diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.h b/llvm/lib/Target/Xtensa/XtensaInstrInfo.h index efd62ff7fa16c..1acd314e2720a 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.h +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.h @@ -35,6 +35,9 @@ class XtensaInstrInfo : public XtensaGenInstrInfo { public: XtensaInstrInfo(const XtensaSubtarget &STI); + void adjustStackPtr(unsigned SP, int64_t Amount, MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const; + // Return the XtensaRegisterInfo, which this class owns. const XtensaRegisterInfo &getRegisterInfo() const { return RI; } @@ -59,6 +62,11 @@ class XtensaInstrInfo : public XtensaGenInstrInfo { void getLoadStoreOpcodes(const TargetRegisterClass *RC, unsigned &LoadOpcode, unsigned &StoreOpcode, int64_t offset) const; + // Emit code before MBBI in MI to move immediate value Value into + // physical register Reg. + void loadImmediate(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, + unsigned *Reg, int64_t Value) const; + const XtensaSubtarget &getSubtarget() const { return STI; } }; } // end namespace llvm diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td index cfdb0220ec663..6e9e75257ccf4 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td @@ -239,6 +239,29 @@ def L32R : RI16_Inst<0x01, (outs AR:$t), (ins L32Rtarget:$label), let imm16 = label; } +// pcrel addr loading using L32R +def : Pat<(Xtensa_pcrel_wrapper tconstpool : $in), (L32R tconstpool : $in)>; + +// FrameIndexes are legalized when they are operands from load/store +// instructions. The same not happens for stack address copies, so an +// add op with mem ComplexPattern is used and the stack address copy +// can be matched. +// Setting of attribute mayLoad is trick to process instruction operands +// in function XtensaRegisterInfo::eliminateFI + +let isCodeGenOnly = 1, mayLoad = 1 in { + + def LEA_ADD : RRI8_Inst<0x02, (outs AR:$t), (ins mem32:$addr), + "addi\t$t, $addr", + [(set AR:$t, addr_ish4:$addr)]> { + bits<12> addr; + + let r = 0x0C; + let imm8{7-0} = addr{11-4}; + let s{3-0} = addr{3-0}; + } +} + //extending loads def : Pat<(i32 (extloadi1 addr_ish1:$addr)), (L8UI addr_ish1:$addr)>; def : Pat<(i32 (extloadi8 addr_ish1:$addr)), (L8UI addr_ish1:$addr)>; @@ -440,6 +463,14 @@ let isReturn = 1, isTerminator = 1, } } +// Call patterns +def : Pat<(Xtensa_call (i32 tglobaladdr:$dst)), + (CALL0 tglobaladdr:$dst)>; +def : Pat<(Xtensa_call (i32 texternalsym:$dst)), + (CALL0 texternalsym:$dst)>; +def : Pat<(Xtensa_call AR:$dst), + (CALLX0 AR:$dst)>; + //===----------------------------------------------------------------------===// // Mem barrier instructions //===----------------------------------------------------------------------===// @@ -512,3 +543,19 @@ def XSR : RSR_Inst<0x00, 0x01, 0x06, (outs AR:$ard, SR:$srd), (ins AR:$t, SR:$sr "xsr\t$t, $sr", []> { let Constraints = "$ard = $t, $srd = $sr"; } + +//===----------------------------------------------------------------------===// +// Stack allocation +//===----------------------------------------------------------------------===// + +// 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. +let Defs = [SP], Uses = [SP] in { + def ADJCALLSTACKDOWN : Pseudo<(outs), (ins i32imm:$amt1, i32imm:$amt2), + "#ADJCALLSTACKDOWN", + [(Xtensa_callseq_start timm:$amt1, timm:$amt2)]>; + def ADJCALLSTACKUP : Pseudo<(outs), (ins i32imm:$amt1, i32imm:$amt2), + "#ADJCALLSTACKUP", + [(Xtensa_callseq_end timm:$amt1, timm:$amt2)]>; +} diff --git a/llvm/lib/Target/Xtensa/XtensaOperands.td b/llvm/lib/Target/Xtensa/XtensaOperands.td index 7a1a2e86e8c20..f41081f9bf2f9 100644 --- a/llvm/lib/Target/Xtensa/XtensaOperands.td +++ b/llvm/lib/Target/Xtensa/XtensaOperands.td @@ -195,7 +195,7 @@ def jumptarget : Operand { let ParserMatchClass = XtensaPCRelTargetAsmOperand; } -def L32Rtarget : Operand { +def L32Rtarget : Operand { let PrintMethod = "printL32RTarget"; let EncoderMethod = "getL32RTargetEncoding"; let DecoderMethod = "decodeL32ROperand"; diff --git a/llvm/lib/Target/Xtensa/XtensaOperators.td b/llvm/lib/Target/Xtensa/XtensaOperators.td index ff82df2260b66..cd4d831c85b58 100644 --- a/llvm/lib/Target/Xtensa/XtensaOperators.td +++ b/llvm/lib/Target/Xtensa/XtensaOperators.td @@ -6,8 +6,31 @@ // //===----------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// +// Type profiles +//===----------------------------------------------------------------------===// +def SDT_XtensaCallSeqStart : SDCallSeqStart<[SDTCisVT<0, i32>, SDTCisVT<1, i32>]>; +def SDT_XtensaCallSeqEnd : SDCallSeqEnd<[SDTCisVT<0, i32>, SDTCisVT<1, i32>]>; +def SDT_XtensaCall : SDTypeProfile<0, -1, [SDTCisPtrTy<0>]>; + +def SDT_XtensaWrapPtr : SDTypeProfile<1, 1, + [SDTCisSameAs<0, 1>, + SDTCisPtrTy<0>]>; + //===----------------------------------------------------------------------===// // Node definitions //===----------------------------------------------------------------------===// +def Xtensa_call: SDNode<"XtensaISD::CALL", SDT_XtensaCall, + [SDNPHasChain, SDNPOutGlue, SDNPOptInGlue, SDNPVariadic]>; + def Xtensa_ret: SDNode<"XtensaISD::RET", SDTNone, [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>; + +def Xtensa_pcrel_wrapper: SDNode<"XtensaISD::PCREL_WRAPPER", SDT_XtensaWrapPtr, []>; + +def Xtensa_callseq_start: SDNode<"ISD::CALLSEQ_START", SDT_XtensaCallSeqStart, + [SDNPHasChain, SDNPSideEffect, SDNPOutGlue]>; + +def Xtensa_callseq_end : SDNode<"ISD::CALLSEQ_END", SDT_XtensaCallSeqEnd, + [SDNPHasChain, SDNPSideEffect, SDNPOptInGlue, + SDNPOutGlue]>; diff --git a/llvm/lib/Target/Xtensa/XtensaRegisterInfo.cpp b/llvm/lib/Target/Xtensa/XtensaRegisterInfo.cpp index 28a61b5d59c98..bced2d4ad0095 100644 --- a/llvm/lib/Target/Xtensa/XtensaRegisterInfo.cpp +++ b/llvm/lib/Target/Xtensa/XtensaRegisterInfo.cpp @@ -64,9 +64,29 @@ bool XtensaRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, MachineInstr &MI = *II; MachineFunction &MF = *MI.getParent()->getParent(); int FrameIndex = MI.getOperand(FIOperandNum).getIndex(); - uint64_t stackSize = MF.getFrameInfo().getStackSize(); - int64_t spOffset = MF.getFrameInfo().getObjectOffset(FrameIndex); - unsigned FrameReg = Xtensa::SP; + uint64_t StackSize = MF.getFrameInfo().getStackSize(); + int64_t SPOffset = MF.getFrameInfo().getObjectOffset(FrameIndex); + MachineFrameInfo &MFI = MF.getFrameInfo(); + const std::vector &CSI = MFI.getCalleeSavedInfo(); + int MinCSFI = 0; + int MaxCSFI = -1; + + if (CSI.size()) { + MinCSFI = CSI[0].getFrameIdx(); + MaxCSFI = CSI[CSI.size() - 1].getFrameIdx(); + } + // The following stack frame objects are always referenced relative to $sp: + // 1. Outgoing arguments. + // 2. Pointer to dynamically allocated stack space. + // 3. Locations for callee-saved registers. + // 4. Locations for eh data registers. + // Everything else is referenced relative to whatever register + // getFrameRegister() returns. + unsigned FrameReg; + if ((FrameIndex >= MinCSFI && FrameIndex <= MaxCSFI)) + FrameReg = Xtensa::SP; + else + FrameReg = getFrameRegister(MF); // Calculate final offset. // - There is no need to change the offset if the frame object is one of the @@ -83,8 +103,23 @@ bool XtensaRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, // If MI is not a debug value, make sure Offset fits in the 16-bit immediate // field. - if (!MI.isDebugValue() && !Valid) - report_fatal_error("Load immediate not supported yet"); + if (!MI.isDebugValue() && !Valid) { + MachineBasicBlock &MBB = *MI.getParent(); + DebugLoc DL = II->getDebugLoc(); + unsigned ADD = Xtensa::ADD; + unsigned Reg; + const XtensaInstrInfo &TII = *static_cast( + MBB.getParent()->getSubtarget().getInstrInfo()); + + TII.loadImmediate(MBB, II, &Reg, Offset); + BuildMI(MBB, II, DL, TII.get(ADD), Reg) + .addReg(FrameReg) + .addReg(Reg, RegState::Kill); + + FrameReg = Reg; + Offset = 0; + IsKill = true; + } MI.getOperand(FIOperandNum).ChangeToRegister(FrameReg, false, false, IsKill); MI.getOperand(FIOperandNum + 1).ChangeToImmediate(Offset); diff --git a/llvm/lib/Target/Xtensa/XtensaUtils.cpp b/llvm/lib/Target/Xtensa/XtensaUtils.cpp index 831b161d1249c..98e424f6ea440 100644 --- a/llvm/lib/Target/Xtensa/XtensaUtils.cpp +++ b/llvm/lib/Target/Xtensa/XtensaUtils.cpp @@ -46,6 +46,8 @@ bool isValidAddrOffset(MachineInstr &MI, int64_t Offset) { case Xtensa::S16I: Scale = 2; break; + case Xtensa::LEA_ADD: + return (Offset >= -128 && Offset <= 127); default: // assume that MI is 32-bit load/store operation Scale = 4; diff --git a/llvm/test/CodeGen/Xtensa/call.ll b/llvm/test/CodeGen/Xtensa/call.ll new file mode 100644 index 0000000000000..24c7c4f558e13 --- /dev/null +++ b/llvm/test/CodeGen/Xtensa/call.ll @@ -0,0 +1,49 @@ +; RUN: llc --mtriple=xtensa < %s | FileCheck %s + +declare i32 @external_function(i32) + +define i32 @test_call_external(i32 %a) nounwind { +; CHECK-LABEL: test_call_external: +; CHECK: # %bb.0: +; CHECK-NEXT: s32i a0, a1, 0 +; CHECK-NEXT: l32r a8, .LCPI0_0 +; CHECK-NEXT: callx0 a8 +; CHECK-NEXT: l32i a0, a1, 0 +; CHECK-NEXT: ret + %1 = call i32 @external_function(i32 %a) + ret i32 %1 +} + +define i32 @defined_function(i32 %a) nounwind { +; CHECK-LABEL: defined_function: +; CHECK: # %bb.0: +; CHECK-NEXT: addi a2, a2, 1 +; CHECK-NEXT: ret + %1 = add i32 %a, 1 + ret i32 %1 +} + +define i32 @test_call_defined(i32 %a) nounwind { +; CHECK-LABEL: test_call_defined: +; CHECK: # %bb.0: +; CHECK-NEXT: s32i a0, a1, 0 +; CHECK-NEXT: l32r a8, .LCPI2_0 +; CHECK-NEXT: callx0 a8 +; CHECK-NEXT: l32i a0, a1, 0 +; CHECK-NEXT: ret + %1 = call i32 @defined_function(i32 %a) nounwind + ret i32 %1 +} + +define i32 @test_call_indirect(ptr %a, i32 %b) nounwind { +; CHECK-LABEL: test_call_indirect: +; CHECK: # %bb.0: +; CHECK-NEXT: s32i a0, a1, 0 +; CHECK-NEXT: or a8, a2, a2 +; CHECK-NEXT: or a2, a3, a3 +; CHECK-NEXT: callx0 a8 +; CHECK-NEXT: l32i a0, a1, 0 +; CHECK-NEXT: ret + %1 = call i32 %a(i32 %b) + ret i32 %1 +} diff --git a/llvm/test/CodeGen/Xtensa/constantpool.ll b/llvm/test/CodeGen/Xtensa/constantpool.ll new file mode 100644 index 0000000000000..9b380d2c37b9e --- /dev/null +++ b/llvm/test/CodeGen/Xtensa/constantpool.ll @@ -0,0 +1,28 @@ +; RUN: llc -mtriple=xtensa -verify-machineinstrs < %s \ +; RUN: | FileCheck %s + +; Test placement of the i32,i64, float and double constants in constantpool + +define dso_local i32 @const_i32() #0 { +; CHECK: .literal_position +; CHECK-NEXT: .literal .LCPI0_0, 74565 +; CHECK-LABEL: const_i32: +; CHECK: l32r a2, .LCPI0_0 + %1 = alloca i32, align 4 + store i32 74565, ptr %1, align 4 + %2 = load i32, ptr %1, align 4 + ret i32 %2 +} + +define dso_local i64 @const_int64() #0 { +; CHECK: .literal_position +; CHECK-NEXT: .literal .LCPI1_0, 305419896 +; CHECK-NEXT: .literal .LCPI1_1, -1859959449 +; CHECK-LABEL: const_int64: +; CHECK: l32r a3, .LCPI1_0 +; CHECK: l32r a2, .LCPI1_1 + %1 = alloca i64, align 8 + store i64 1311768467302729063, ptr %1, align 8 + %2 = load i64, ptr %1, align 8 + ret i64 %2 +} diff --git a/llvm/test/MC/Xtensa/Core/invalid.s b/llvm/test/MC/Xtensa/Core/invalid.s index d3d8fba8169a6..c7473e90c10ba 100644 --- a/llvm/test/MC/Xtensa/Core/invalid.s +++ b/llvm/test/MC/Xtensa/Core/invalid.s @@ -4,10 +4,6 @@ LBL0: # Out of range immediates -# imm12m -movi a1, 3000 -# CHECK: :[[#@LINE-1]]:10: error: expected immediate in range [-2048, 2047] - # imm8 addi a1, a2, 300 # CHECK: :[[#@LINE-1]]:14: error: expected immediate in range [-128, 127] diff --git a/llvm/test/MC/Xtensa/directive-literal.s b/llvm/test/MC/Xtensa/directive-literal.s new file mode 100644 index 0000000000000..269cf20ed45eb --- /dev/null +++ b/llvm/test/MC/Xtensa/directive-literal.s @@ -0,0 +1,42 @@ +# RUN: llvm-mc -triple=xtensa -filetype obj -o - %s \ +# RUN: | llvm-readobj -S --sd - \ +# RUN: | FileCheck -check-prefix=CHECK-LITERAL %s + +# RUN: llvm-mc %s -triple=xtensa -show-encoding \ +# RUN: | FileCheck -check-prefix=CHECK-INST %s + + .text + .literal_position + .literal .LCPI0_0, 305419896 + .literal .LCPI1_0, ext_var + .global test_literal + .p2align 2 + .type test_literal,@function +test_literal: + l32r a2, .LCPI0_0 + l32r a3, .LCPI1_0 + movi a4, 30000 + movi a5, 1000 + ret + +# CHECK-LITERAL: Section { +# CHECK-LITERAL: Name: .literal +# CHECK-LITERAL: SectionData ( +# CHECK-LITERAL: 0000: 78563412 00000000 30750000 +# CHECK-LITERAL: ) +# CHECK-LITERAL: } + +# CHECK-INST: .literal_position +# CHECK-INST: .literal .LCPI0_0, 305419896 +# CHECK-INST: .literal .LCPI1_0, ext_var +# CHECK-INST: .global test_literal +# CHECK-INST: .p2align 2 +# CHECK-INST: .type test_literal,@function +# CHECK-INST: test_literal: +# CHECK-INST: l32r a2, .LCPI0_0 +# CHECK-INST: l32r a3, .LCPI1_0 +# CHECK-INST: .literal .Ltmp0, 30000 +# CHECK-INST: l32r a4, .Ltmp0 +# CHECK-INST: movi a5, 1000 +# CHECK-INST: ret + From 393aa32f1a3677b12fd700d365fff6f6ba792ca6 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 20 Mar 2024 17:49:13 +0300 Subject: [PATCH 3/6] [Xtensa] Fix callconv, constantpool, etc Fix type promotion in callconv implementation. Minor fixes in constantpool, targetstreamer and asmparser. Fix minor format issues. --- .../Xtensa/AsmParser/XtensaAsmParser.cpp | 21 +++--- .../MCTargetDesc/XtensaMCTargetDesc.cpp | 2 +- .../MCTargetDesc/XtensaTargetStreamer.cpp | 18 ++--- .../MCTargetDesc/XtensaTargetStreamer.h | 2 - llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp | 65 +++++++++-------- llvm/lib/Target/Xtensa/XtensaCallingConv.td | 3 - .../Target/Xtensa/XtensaConstantPoolValue.cpp | 7 +- .../Target/Xtensa/XtensaConstantPoolValue.h | 3 +- llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 69 ++++--------------- 9 files changed, 67 insertions(+), 123 deletions(-) diff --git a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp index 9fd05ee96a929..d706b6ad61f8c 100644 --- a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp +++ b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp @@ -162,12 +162,7 @@ struct XtensaOperand : public MCParsedAsmOperand { bool isImm12() const { return isImm(-2048, 2047); } // Convert MOVI to literal load, when immediate is not in range (-2048, 2047) - bool isImm12m() const { - if (Kind == Immediate) - return true; - - return false; - } + bool isImm12m() const { return Kind == Immediate; } bool isOffset4m32() const { return isImm(0, 60) && @@ -375,7 +370,7 @@ bool XtensaAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, switch (Opcode) { case Xtensa::L32R: { const MCSymbolRefExpr *OpExpr = - (const MCSymbolRefExpr *)Inst.getOperand(1).getExpr(); + static_cast(Inst.getOperand(1).getExpr()); XtensaMCExpr::VariantKind Kind = XtensaMCExpr::VK_Xtensa_None; const MCExpr *NewOpExpr = XtensaMCExpr::create(OpExpr, Kind, getContext()); Inst.getOperand(1).setExpr(NewOpExpr); @@ -387,7 +382,7 @@ bool XtensaAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, if (!Inst.getOperand(1).isExpr()) { uint64_t ImmOp64 = Inst.getOperand(1).getImm(); int32_t Imm = ImmOp64; - if ((Imm < -2048) || (Imm > 2047)) { + if (!isInt<12>(Imm)) { XtensaTargetStreamer &TS = this->getTargetStreamer(); MCInst TmpInst; TmpInst.setLoc(IDLoc); @@ -420,7 +415,8 @@ bool XtensaAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, Inst = TmpInst; TS.emitLiteral(Sym, Value, IDLoc); } - } break; + break; + } default: break; } @@ -769,7 +765,6 @@ bool XtensaAsmParser::ParseInstruction(ParseInstructionInfo &Info, bool XtensaAsmParser::parseLiteralDirective(SMLoc L) { MCAsmParser &Parser = getParser(); - MCSymbol *Sym; const MCExpr *Value; SMLoc LiteralLoc = getLexer().getLoc(); XtensaTargetStreamer &TS = this->getTargetStreamer(); @@ -778,11 +773,9 @@ bool XtensaAsmParser::parseLiteralDirective(SMLoc L) { return true; const MCSymbolRefExpr *SE = dyn_cast(Value); + if (!SE) return Error(LiteralLoc, "literal label must be a symbol"); - else { - Sym = getContext().getOrCreateSymbol(SE->getSymbol().getName()); - } if (Parser.parseToken(AsmToken::Comma, "expected comma")) return true; @@ -794,6 +787,8 @@ bool XtensaAsmParser::parseLiteralDirective(SMLoc L) { if (Parser.parseExpression(Value)) return true; + MCSymbol *Sym = getContext().getOrCreateSymbol(SE->getSymbol().getName()); + TS.emitLiteral(Sym, Value, LiteralLoc); return false; diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp index 8914ebf658cc4..87ef66ba742b6 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp @@ -8,10 +8,10 @@ // //===----------------------------------------------------------------------===// #include "XtensaMCTargetDesc.h" +#include "TargetInfo/XtensaTargetInfo.h" #include "XtensaInstPrinter.h" #include "XtensaMCAsmInfo.h" #include "XtensaTargetStreamer.h" -#include "TargetInfo/XtensaTargetInfo.h" #include "llvm/ADT/STLExtras.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCInstrInfo.h" diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaTargetStreamer.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaTargetStreamer.cpp index 4163e64de48f0..fa7d36096b595 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaTargetStreamer.cpp +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaTargetStreamer.cpp @@ -1,7 +1,5 @@ //===-- XtensaTargetStreamer.cpp - Xtensa Target Streamer Methods ---------===// // -// The LLVM Compiler Infrastructure -// // 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 @@ -48,16 +46,20 @@ void XtensaTargetAsmStreamer::emitLiteralPosition() { XtensaTargetELFStreamer::XtensaTargetELFStreamer(MCStreamer &S) : XtensaTargetStreamer(S) {} -static std::string getLiteralSectionName(std::string CSectionName) { +static std::string getLiteralSectionName(StringRef CSectionName) { std::size_t Pos = CSectionName.find(".text"); std::string SectionName; if (Pos != std::string::npos) { + SectionName = CSectionName.substr(0, Pos); + if (Pos > 0) - SectionName = CSectionName.substr(0, Pos + 5); - else - SectionName = ""; + SectionName += ".text"; + + CSectionName = CSectionName.drop_front(Pos); + CSectionName.consume_front(".text"); + SectionName += ".literal"; - SectionName += CSectionName.substr(Pos + 5); + SectionName += CSectionName; } else { SectionName = CSectionName; SectionName += ".literal"; @@ -70,7 +72,7 @@ void XtensaTargetELFStreamer::emitLiteral(MCSymbol *LblSym, const MCExpr *Value, MCContext &Context = getStreamer().getContext(); MCStreamer &OutStreamer = getStreamer(); MCSectionELF *CS = (MCSectionELF *)OutStreamer.getCurrentSectionOnly(); - std::string SectionName = getLiteralSectionName(CS->getName().str()); + std::string SectionName = getLiteralSectionName(CS->getName()); MCSection *ConstSection = Context.getELFSection( SectionName, ELF::SHT_PROGBITS, ELF::SHF_EXECINSTR | ELF::SHF_ALLOC); diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaTargetStreamer.h b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaTargetStreamer.h index a7d8b6dd9c792..0ea847688d179 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaTargetStreamer.h +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaTargetStreamer.h @@ -1,7 +1,5 @@ //===-- XtensaTargetStreamer.h - Xtensa Target Streamer --------*- C++ -*--===// // -// The LLVM Compiler Infrastructure -// // 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 diff --git a/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp b/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp index 3c8977a742eae..a172f687e0b0e 100644 --- a/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp +++ b/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp @@ -136,41 +136,40 @@ void XtensaAsmPrinter::emitConstantPool() { if (CP.empty()) return; - for (unsigned i = 0, e = CP.size(); i != e; ++i) { - const MachineConstantPoolEntry &CPE = CP[i]; - - if (i == 0) { - if (OutStreamer->hasRawTextSupport()) { - OutStreamer->switchSection( - getObjFileLowering().SectionForGlobal(&F, TM)); - OutStreamer->emitRawText(StringRef("\t.literal_position\n")); - } else { - MCSectionELF *CS = - (MCSectionELF *)getObjFileLowering().SectionForGlobal(&F, TM); - std::string CSectionName = CS->getName().str(); - std::size_t Pos = CSectionName.find(".text"); - std::string SectionName; - if (Pos != std::string::npos) { - if (Pos > 0) - SectionName = CSectionName.substr(0, Pos + 5); - else - SectionName = ""; - SectionName += ".literal"; - SectionName += CSectionName.substr(Pos + 5); - } else { - SectionName = CSectionName; - SectionName += ".literal"; - } - - MCSectionELF *S = - OutContext.getELFSection(SectionName, ELF::SHT_PROGBITS, - ELF::SHF_EXECINSTR | ELF::SHF_ALLOC); - S->setAlignment(Align(4)); - OutStreamer->switchSection(S); - } + if (OutStreamer->hasRawTextSupport()) { + OutStreamer->switchSection(getObjFileLowering().SectionForGlobal(&F, TM)); + OutStreamer->emitRawText(StringRef("\t.literal_position\n")); + } else { + MCSectionELF *CS = + (MCSectionELF *)getObjFileLowering().SectionForGlobal(&F, TM); + StringRef CSectionName = CS->getName(); + std::size_t Pos = CSectionName.find(".text"); + std::string SectionName; + if (Pos != std::string::npos) { + SectionName = CSectionName.substr(0, Pos); + + if (Pos > 0) + SectionName += ".text"; + + CSectionName = CSectionName.drop_front(Pos); + CSectionName.consume_front(".text"); + + SectionName += ".literal"; + SectionName += CSectionName; + } else { + SectionName = CSectionName; + SectionName += ".literal"; } - emitMachineConstantPoolEntry(CPE, i); + MCSectionELF *S = OutContext.getELFSection( + SectionName, ELF::SHT_PROGBITS, ELF::SHF_EXECINSTR | ELF::SHF_ALLOC); + S->setAlignment(Align(4)); + OutStreamer->switchSection(S); + } + + int CPIdx = 0; + for (const MachineConstantPoolEntry &CPE : CP) { + emitMachineConstantPoolEntry(CPE, CPIdx++); } } diff --git a/llvm/lib/Target/Xtensa/XtensaCallingConv.td b/llvm/lib/Target/Xtensa/XtensaCallingConv.td index 7da3eb6dd6585..a348b4c890b22 100644 --- a/llvm/lib/Target/Xtensa/XtensaCallingConv.td +++ b/llvm/lib/Target/Xtensa/XtensaCallingConv.td @@ -12,9 +12,6 @@ // Xtensa return value calling convention //===----------------------------------------------------------------------===// def RetCC_Xtensa : CallingConv<[ - CCIfType<[i1, i8, i16], CCPromoteToType>, - CCIfType<[f32], CCBitConvertToType>, - // First two return values go in a2, a3, a4, a5 CCIfType<[i32], CCAssignToReg<[A2, A3, A4, A5]>>, CCIfType<[i64], CCAssignToRegWithShadow<[A2, A4], [A3, A5]>> diff --git a/llvm/lib/Target/Xtensa/XtensaConstantPoolValue.cpp b/llvm/lib/Target/Xtensa/XtensaConstantPoolValue.cpp index 1cb1e577ae045..902b29c4e767a 100644 --- a/llvm/lib/Target/Xtensa/XtensaConstantPoolValue.cpp +++ b/llvm/lib/Target/Xtensa/XtensaConstantPoolValue.cpp @@ -72,8 +72,7 @@ void XtensaConstantPoolValue::print(raw_ostream &O) const {} XtensaConstantPoolConstant::XtensaConstantPoolConstant( const Constant *C, unsigned ID, XtensaCP::XtensaCPKind Kind) - : XtensaConstantPoolValue((Type *)C->getType(), ID, Kind), - CVal(C) {} + : XtensaConstantPoolValue((Type *)C->getType(), ID, Kind), CVal(C) {} XtensaConstantPoolConstant * XtensaConstantPoolConstant::Create(const Constant *C, unsigned ID, @@ -147,8 +146,7 @@ void XtensaConstantPoolSymbol::print(raw_ostream &O) const { XtensaConstantPoolMBB::XtensaConstantPoolMBB(LLVMContext &C, const MachineBasicBlock *mbb, unsigned id) - : XtensaConstantPoolValue(C, 0, XtensaCP::CPMachineBasicBlock), - MBB(mbb) {} + : XtensaConstantPoolValue(C, 0, XtensaCP::CPMachineBasicBlock), MBB(mbb) {} XtensaConstantPoolMBB * XtensaConstantPoolMBB::Create(LLVMContext &C, const MachineBasicBlock *mbb, @@ -205,4 +203,3 @@ void XtensaConstantPoolJumpTable::print(raw_ostream &O) const { O << "JT" << IDX; XtensaConstantPoolValue::print(O); } - diff --git a/llvm/lib/Target/Xtensa/XtensaConstantPoolValue.h b/llvm/lib/Target/Xtensa/XtensaConstantPoolValue.h index c92ee5fd5f0e7..8c80b0e0dbb44 100644 --- a/llvm/lib/Target/Xtensa/XtensaConstantPoolValue.h +++ b/llvm/lib/Target/Xtensa/XtensaConstantPoolValue.h @@ -48,7 +48,7 @@ enum XtensaCPModifier { class XtensaConstantPoolValue : public MachineConstantPoolValue { unsigned LabelId; // Label id of the load. XtensaCP::XtensaCPKind Kind; // Kind of constant. - XtensaCP::XtensaCPModifier Modifier; // Symbol name modifier + XtensaCP::XtensaCPModifier Modifier; // Symbol name modifier //(for example Global Variable name) protected: @@ -154,7 +154,6 @@ class XtensaConstantPoolConstant : public XtensaConstantPoolValue { } }; - /// XtensaConstantPoolSymbol - Xtensa-specific constantpool values for external /// symbols. class XtensaConstantPoolSymbol : public XtensaConstantPoolValue { diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp index ee0618d577a07..009dbb1794569 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp @@ -11,8 +11,8 @@ // //===----------------------------------------------------------------------===// -#include "XtensaConstantPoolValue.h" #include "XtensaISelLowering.h" +#include "XtensaConstantPoolValue.h" #include "XtensaSubtarget.h" #include "XtensaTargetMachine.h" #include "llvm/CodeGen/CallingConvLower.h" @@ -57,6 +57,17 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &TM, 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); @@ -157,53 +168,6 @@ CCAssignFn *XtensaTargetLowering::CCAssignFnForCall(CallingConv::ID CC, return CC_Xtensa_Custom; } -// Value is a value that has been passed to us in the location described by VA -// (and so has type VA.getLocVT()). Convert Value to VA.getValVT(), chaining -// any loads onto Chain. -static SDValue convertLocVTToValVT(SelectionDAG &DAG, const SDLoc &DL, - CCValAssign &VA, SDValue Chain, - SDValue Value) { - // If the argument has been promoted from a smaller type, insert an - // assertion to capture this. - if (VA.getLocInfo() == CCValAssign::SExt) - Value = DAG.getNode(ISD::AssertSext, DL, VA.getLocVT(), Value, - DAG.getValueType(VA.getValVT())); - else if (VA.getLocInfo() == CCValAssign::ZExt) - Value = DAG.getNode(ISD::AssertZext, DL, VA.getLocVT(), Value, - DAG.getValueType(VA.getValVT())); - - if (VA.isExtInLoc()) - Value = DAG.getNode(ISD::TRUNCATE, DL, VA.getValVT(), Value); - else if (VA.getLocInfo() == CCValAssign::Indirect) - Value = DAG.getLoad(VA.getValVT(), DL, Chain, Value, MachinePointerInfo()); - else if (VA.getValVT() == MVT::f32) - Value = DAG.getNode(ISD::BITCAST, DL, VA.getValVT(), Value); - else - assert(VA.getLocInfo() == CCValAssign::Full && "Unsupported getLocInfo"); - return Value; -} - -// Value is a value of type VA.getValVT() that we need to copy into -// the location described by VA. Return a copy of Value converted to -// VA.getValVT(). The caller is responsible for handling indirect values. -static SDValue convertValVTToLocVT(SelectionDAG &DAG, SDLoc DL, CCValAssign &VA, - SDValue Value) { - switch (VA.getLocInfo()) { - case CCValAssign::SExt: - return DAG.getNode(ISD::SIGN_EXTEND, DL, VA.getLocVT(), Value); - case CCValAssign::ZExt: - return DAG.getNode(ISD::ZERO_EXTEND, DL, VA.getLocVT(), Value); - case CCValAssign::AExt: - return DAG.getNode(ISD::ANY_EXTEND, DL, VA.getLocVT(), Value); - case CCValAssign::BCvt: - return DAG.getNode(ISD::BITCAST, DL, VA.getLocVT(), Value); - case CCValAssign::Full: - return Value; - default: - report_fatal_error("Unhandled getLocInfo()"); - } -} - SDValue XtensaTargetLowering::LowerFormalArguments( SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, const SmallVectorImpl &Ins, const SDLoc &DL, @@ -340,8 +304,6 @@ XtensaTargetLowering::LowerCall(CallLoweringInfo &CLI, SDValue ArgValue = OutVals[I]; ISD::ArgFlagsTy Flags = Outs[I].Flags; - ArgValue = convertValVTToLocVT(DAG, DL, VA, ArgValue); - if (VA.isRegLoc()) // Queue up the argument copies and emit them at the end. RegsToPass.push_back(std::make_pair(VA.getLocReg(), ArgValue)); @@ -468,9 +430,7 @@ XtensaTargetLowering::LowerCall(CallLoweringInfo &CLI, Chain = RetValue.getValue(1); Glue = RetValue.getValue(2); - // Convert the value of the return register into the value that's - // being returned. - InVals.push_back(convertLocVTToValVT(DAG, DL, VA, Chain, RetValue)); + InVals.push_back(RetValue); } return Chain; } @@ -514,9 +474,6 @@ XtensaTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv, // Make the return register live on exit. assert(VA.isRegLoc() && "Can only return in registers!"); - // Promote the value as required. - RetValue = convertValVTToLocVT(DAG, DL, VA, RetValue); - // Chain and glue the copies together. unsigned Register = VA.getLocReg(); Chain = DAG.getCopyToReg(Chain, DL, Register, RetValue, Glue); From 9d48072a977bdf3693d541d060e32b370bb562ab Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Wed, 20 Mar 2024 20:04:14 +0300 Subject: [PATCH 4/6] [Xtensa] Fix asm printer. Use SmallString instead of std::string. --- llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp | 25 +++++++++++---------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp b/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp index a172f687e0b0e..b8ed30b1fc005 100644 --- a/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp +++ b/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp @@ -63,15 +63,15 @@ void XtensaAsmPrinter::emitMachineConstantPoolValue( MCSymbol *LblSym = GetCPISymbol(ACPV->getLabelId()); // TODO find a better way to check whether we emit data to .s file if (OutStreamer->hasRawTextSupport()) { - std::string SymName("\t.literal "); - SymName += LblSym->getName(); - SymName += ", "; - SymName += MCSym->getName(); + SmallString<60> Str; + raw_svector_ostream LiteralStr(Str); + LiteralStr << "\t.literal " << LblSym->getName() << ", " + << MCSym->getName(); StringRef Modifier = ACPV->getModifierText(); - SymName += Modifier; + LiteralStr << Modifier; - OutStreamer->emitRawText(StringRef(SymName)); + OutStreamer->emitRawText(StringRef(LiteralStr.str())); } else { MCSymbolRefExpr::VariantKind VK = getModifierVariantKind(ACPV->getModifier()); @@ -101,21 +101,22 @@ void XtensaAsmPrinter::emitMachineConstantPoolEntry( MCSymbol *LblSym = GetCPISymbol(i); // TODO find a better way to check whether we emit data to .s file if (OutStreamer->hasRawTextSupport()) { - std::string str("\t.literal "); - str += LblSym->getName(); - str += ", "; + SmallString<60> Str; + raw_svector_ostream LiteralStr(Str); + LiteralStr << "\t.literal " << LblSym->getName() << ", "; + const Constant *C = CPE.Val.ConstVal; if (const auto *CFP = dyn_cast(C)) { - str += toString(CFP->getValueAPF().bitcastToAPInt(), 10, true); + LiteralStr << toString(CFP->getValueAPF().bitcastToAPInt(), 10, true); } else if (const auto *CI = dyn_cast(C)) { - str += toString(CI->getValue(), 10, true); + LiteralStr << toString(CI->getValue(), 10, true); } else { report_fatal_error( "This constant type is not supported yet in constantpool"); } - OutStreamer->emitRawText(StringRef(str)); + OutStreamer->emitRawText(StringRef(LiteralStr.str())); } else { OutStreamer->emitCodeAlignment( Align(4), OutStreamer->getContext().getSubtargetInfo()); From c5f9a64c6284f9dbd82b56e681c8541adc345ca8 Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Thu, 11 Apr 2024 10:26:43 +0300 Subject: [PATCH 5/6] [Xtensa] Improve TargetStreamer, code formatting. Move some functionality from AsmPrinter to the TargetStreamer. Add test for "literal" asm directive. Code formatting. --- .../Xtensa/AsmParser/XtensaAsmParser.cpp | 27 +++-- .../MCTargetDesc/XtensaTargetStreamer.cpp | 96 +++++++++------ .../MCTargetDesc/XtensaTargetStreamer.h | 22 +++- llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp | 112 ++++++------------ .../Target/Xtensa/XtensaConstantPoolValue.cpp | 50 ++++---- .../Target/Xtensa/XtensaConstantPoolValue.h | 37 +++--- llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp | 6 +- llvm/test/MC/Xtensa/invalid-literal.s | 10 ++ 8 files changed, 188 insertions(+), 172 deletions(-) create mode 100644 llvm/test/MC/Xtensa/invalid-literal.s diff --git a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp index d706b6ad61f8c..f4dec5fa12d53 100644 --- a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp +++ b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp @@ -43,7 +43,7 @@ class XtensaAsmParser : public MCTargetAsmParser { return static_cast(TS); } - bool ParseDirective(AsmToken DirectiveID) override; + ParseStatus parseDirective(AsmToken DirectiveID) override; bool parseRegister(MCRegister &Reg, SMLoc &StartLoc, SMLoc &EndLoc) override; bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name, SMLoc NameLoc, OperandVector &Operands) override; @@ -374,7 +374,8 @@ bool XtensaAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, XtensaMCExpr::VariantKind Kind = XtensaMCExpr::VK_Xtensa_None; const MCExpr *NewOpExpr = XtensaMCExpr::create(OpExpr, Kind, getContext()); Inst.getOperand(1).setExpr(NewOpExpr); - } break; + break; + } case Xtensa::MOVI: { XtensaTargetStreamer &TS = this->getTargetStreamer(); @@ -396,7 +397,7 @@ bool XtensaAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, TmpInst.addOperand(Inst.getOperand(0)); MCOperand Op1 = MCOperand::createExpr(OpExpr); TmpInst.addOperand(Op1); - TS.emitLiteral(Sym, Value, IDLoc); + TS.emitLiteral(Sym, Value, true, IDLoc); Inst = TmpInst; } } else { @@ -413,7 +414,7 @@ bool XtensaAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, MCOperand Op1 = MCOperand::createExpr(OpExpr); TmpInst.addOperand(Op1); Inst = TmpInst; - TS.emitLiteral(Sym, Value, IDLoc); + TS.emitLiteral(Sym, Value, true, IDLoc); } break; } @@ -777,7 +778,7 @@ bool XtensaAsmParser::parseLiteralDirective(SMLoc L) { if (!SE) return Error(LiteralLoc, "literal label must be a symbol"); - if (Parser.parseToken(AsmToken::Comma, "expected comma")) + if (Parser.parseComma()) return true; SMLoc OpcodeLoc = getLexer().getLoc(); @@ -787,31 +788,31 @@ bool XtensaAsmParser::parseLiteralDirective(SMLoc L) { if (Parser.parseExpression(Value)) return true; + if (parseEOL()) + return true; + MCSymbol *Sym = getContext().getOrCreateSymbol(SE->getSymbol().getName()); - TS.emitLiteral(Sym, Value, LiteralLoc); + TS.emitLiteral(Sym, Value, true, LiteralLoc); return false; } -bool XtensaAsmParser::ParseDirective(AsmToken DirectiveID) { +ParseStatus XtensaAsmParser::parseDirective(AsmToken DirectiveID) { StringRef IDVal = DirectiveID.getString(); SMLoc Loc = getLexer().getLoc(); if (IDVal == ".literal_position") { XtensaTargetStreamer &TS = this->getTargetStreamer(); TS.emitLiteralPosition(); - Lex(); - return false; + return parseEOL(); } if (IDVal == ".literal") { - parseLiteralDirective(Loc); - Lex(); - return false; + return parseLiteralDirective(Loc); } - return true; + return ParseStatus::NoMatch; } // Force static initialization. diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaTargetStreamer.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaTargetStreamer.cpp index fa7d36096b595..0ea70cff4d404 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaTargetStreamer.cpp +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaTargetStreamer.cpp @@ -17,10 +17,32 @@ #include "llvm/MC/MCContext.h" #include "llvm/MC/MCObjectFileInfo.h" #include "llvm/MC/MCSectionELF.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/FormattedStream.h" using namespace llvm; +static std::string getLiteralSectionName(StringRef CSectionName) { + std::size_t Pos = CSectionName.find(".text"); + std::string SectionName; + if (Pos != std::string::npos) { + SectionName = CSectionName.substr(0, Pos); + + if (Pos > 0) + SectionName += ".text"; + + CSectionName = CSectionName.drop_front(Pos); + CSectionName.consume_front(".text"); + + SectionName += ".literal"; + SectionName += CSectionName; + } else { + SectionName = CSectionName; + SectionName += ".literal"; + } + return SectionName; +} + XtensaTargetStreamer::XtensaTargetStreamer(MCStreamer &S) : MCTargetStreamer(S) {} @@ -29,59 +51,67 @@ XtensaTargetAsmStreamer::XtensaTargetAsmStreamer(MCStreamer &S, : XtensaTargetStreamer(S), OS(OS) {} void XtensaTargetAsmStreamer::emitLiteral(MCSymbol *LblSym, const MCExpr *Value, - SMLoc L) { - const MCAsmInfo *MAI = Streamer.getContext().getAsmInfo(); - - OS << "\t.literal\t"; - LblSym->print(OS, MAI); - OS << ", "; - Value->print(OS, MAI); - OS << '\n'; + bool SwitchLiteralSection, SMLoc L) { + SmallString<60> Str; + raw_svector_ostream LiteralStr(Str); + + LiteralStr << "\t.literal " << LblSym->getName() << ", "; + + if (auto CE = dyn_cast(Value)) { + LiteralStr << CE->getValue() << "\n"; + } else if (auto SRE = dyn_cast(Value)) { + const MCSymbol &Sym = SRE->getSymbol(); + LiteralStr << Sym.getName() << "\n"; + } else { + llvm_unreachable("unexpected constant pool entry type"); + } + + OS << LiteralStr.str(); } void XtensaTargetAsmStreamer::emitLiteralPosition() { OS << "\t.literal_position\n"; } +void XtensaTargetAsmStreamer::startLiteralSection(MCSection *BaseSection) { + emitLiteralPosition(); +} + XtensaTargetELFStreamer::XtensaTargetELFStreamer(MCStreamer &S) : XtensaTargetStreamer(S) {} -static std::string getLiteralSectionName(StringRef CSectionName) { - std::size_t Pos = CSectionName.find(".text"); - std::string SectionName; - if (Pos != std::string::npos) { - SectionName = CSectionName.substr(0, Pos); +void XtensaTargetELFStreamer::emitLiteral(MCSymbol *LblSym, const MCExpr *Value, + bool SwitchLiteralSection, SMLoc L) { + MCStreamer &OutStreamer = getStreamer(); + if (SwitchLiteralSection) { + MCContext &Context = OutStreamer.getContext(); + auto *CS = static_cast(OutStreamer.getCurrentSectionOnly()); + std::string SectionName = getLiteralSectionName(CS->getName()); - if (Pos > 0) - SectionName += ".text"; + MCSection *ConstSection = Context.getELFSection( + SectionName, ELF::SHT_PROGBITS, ELF::SHF_EXECINSTR | ELF::SHF_ALLOC); - CSectionName = CSectionName.drop_front(Pos); - CSectionName.consume_front(".text"); + OutStreamer.pushSection(); + OutStreamer.switchSection(ConstSection); + } - SectionName += ".literal"; - SectionName += CSectionName; - } else { - SectionName = CSectionName; - SectionName += ".literal"; + OutStreamer.emitLabel(LblSym, L); + OutStreamer.emitValue(Value, 4, L); + + if (SwitchLiteralSection) { + OutStreamer.popSection(); } - return SectionName; } -void XtensaTargetELFStreamer::emitLiteral(MCSymbol *LblSym, const MCExpr *Value, - SMLoc L) { +void XtensaTargetELFStreamer::startLiteralSection(MCSection *BaseSection) { MCContext &Context = getStreamer().getContext(); - MCStreamer &OutStreamer = getStreamer(); - MCSectionELF *CS = (MCSectionELF *)OutStreamer.getCurrentSectionOnly(); - std::string SectionName = getLiteralSectionName(CS->getName()); + + std::string SectionName = getLiteralSectionName(BaseSection->getName()); MCSection *ConstSection = Context.getELFSection( SectionName, ELF::SHT_PROGBITS, ELF::SHF_EXECINSTR | ELF::SHF_ALLOC); - OutStreamer.pushSection(); - OutStreamer.switchSection(ConstSection); - OutStreamer.emitLabel(LblSym, L); - OutStreamer.emitValue(Value, 4, L); - OutStreamer.popSection(); + ConstSection->setAlignment(Align(4)); } MCELFStreamer &XtensaTargetELFStreamer::getStreamer() { diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaTargetStreamer.h b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaTargetStreamer.h index 0ea847688d179..817940e880b3c 100644 --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaTargetStreamer.h +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaTargetStreamer.h @@ -19,8 +19,18 @@ class formatted_raw_ostream; class XtensaTargetStreamer : public MCTargetStreamer { public: XtensaTargetStreamer(MCStreamer &S); - virtual void emitLiteral(MCSymbol *LblSym, const MCExpr *Value, SMLoc L) = 0; + + // Emit literal label and literal Value to the literal section. If literal + // section is not switched yet (SwitchLiteralSection is true) then switch to + // literal section. + virtual void emitLiteral(MCSymbol *LblSym, const MCExpr *Value, + bool SwitchLiteralSection, SMLoc L = SMLoc()) = 0; + virtual void emitLiteralPosition() = 0; + + // Switch to the literal section. The BaseSection name is used to construct + // literal section name. + virtual void startLiteralSection(MCSection *BaseSection) = 0; }; class XtensaTargetAsmStreamer : public XtensaTargetStreamer { @@ -28,17 +38,21 @@ class XtensaTargetAsmStreamer : public XtensaTargetStreamer { public: XtensaTargetAsmStreamer(MCStreamer &S, formatted_raw_ostream &OS); - void emitLiteral(MCSymbol *LblSym, const MCExpr *Value, SMLoc L) override; + void emitLiteral(MCSymbol *LblSym, const MCExpr *Value, + bool SwitchLiteralSection, SMLoc L) override; void emitLiteralPosition() override; + void startLiteralSection(MCSection *Section) override; }; class XtensaTargetELFStreamer : public XtensaTargetStreamer { public: XtensaTargetELFStreamer(MCStreamer &S); MCELFStreamer &getStreamer(); - void emitLiteral(MCSymbol *LblSym, const MCExpr *Value, SMLoc L) override; + void emitLiteral(MCSymbol *LblSym, const MCExpr *Value, + bool SwitchLiteralSection, SMLoc L) override; void emitLiteralPosition() override {} + void startLiteralSection(MCSection *Section) override; }; } // end namespace llvm -#endif +#endif // LLVM_LIB_TARGET_XTENSA_XTENSATARGETSTREAMER_H diff --git a/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp b/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp index b8ed30b1fc005..e222919b28dc9 100644 --- a/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp +++ b/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp @@ -13,6 +13,7 @@ #include "XtensaAsmPrinter.h" #include "MCTargetDesc/XtensaMCExpr.h" +#include "MCTargetDesc/XtensaTargetStreamer.h" #include "TargetInfo/XtensaTargetInfo.h" #include "XtensaConstantPoolValue.h" #include "llvm/ADT/StringExtras.h" @@ -56,38 +57,25 @@ void XtensaAsmPrinter::emitMachineConstantPoolValue( XtensaConstantPoolSymbol *XtensaSym = cast(ACPV); const char *Sym = XtensaSym->getSymbol(); std::string SymName(Sym); + if (XtensaSym->isPrivateLinkage()) SymName = ".L" + SymName; - MCSym = GetExternalSymbolSymbol(StringRef(SymName)); + MCSym = GetExternalSymbolSymbol(StringRef(SymName)); MCSymbol *LblSym = GetCPISymbol(ACPV->getLabelId()); - // TODO find a better way to check whether we emit data to .s file - if (OutStreamer->hasRawTextSupport()) { - SmallString<60> Str; - raw_svector_ostream LiteralStr(Str); - LiteralStr << "\t.literal " << LblSym->getName() << ", " - << MCSym->getName(); + auto *TS = + static_cast(OutStreamer->getTargetStreamer()); + MCSymbolRefExpr::VariantKind VK = getModifierVariantKind(ACPV->getModifier()); + if (ACPV->getModifier() != XtensaCP::no_modifier) { + std::string SymName(MCSym->getName()); StringRef Modifier = ACPV->getModifierText(); - LiteralStr << Modifier; - - OutStreamer->emitRawText(StringRef(LiteralStr.str())); - } else { - MCSymbolRefExpr::VariantKind VK = - getModifierVariantKind(ACPV->getModifier()); - - if (ACPV->getModifier() != XtensaCP::no_modifier) { - std::string SymName(MCSym->getName()); - MCSym = GetExternalSymbolSymbol(StringRef(SymName)); - } - - const MCExpr *Expr = MCSymbolRefExpr::create(MCSym, VK, OutContext); - uint64_t Size = getDataLayout().getTypeAllocSize(ACPV->getType()); - OutStreamer->emitCodeAlignment( - Align(4), OutStreamer->getContext().getSubtargetInfo()); - OutStreamer->emitLabel(LblSym); - OutStreamer->emitValue(Expr, Size); + SymName += Modifier; + MCSym = GetExternalSymbolSymbol(StringRef(SymName)); } + + const MCExpr *Expr = MCSymbolRefExpr::create(MCSym, VK, OutContext); + TS->emitLiteral(LblSym, Expr, false); } void XtensaAsmPrinter::emitMachineConstantPoolEntry( @@ -99,30 +87,24 @@ void XtensaAsmPrinter::emitMachineConstantPoolEntry( emitMachineConstantPoolValue(CPE.Val.MachineCPVal); } else { MCSymbol *LblSym = GetCPISymbol(i); - // TODO find a better way to check whether we emit data to .s file - if (OutStreamer->hasRawTextSupport()) { - SmallString<60> Str; - raw_svector_ostream LiteralStr(Str); - LiteralStr << "\t.literal " << LblSym->getName() << ", "; - - const Constant *C = CPE.Val.ConstVal; - - if (const auto *CFP = dyn_cast(C)) { - LiteralStr << toString(CFP->getValueAPF().bitcastToAPInt(), 10, true); - } else if (const auto *CI = dyn_cast(C)) { - LiteralStr << toString(CI->getValue(), 10, true); - } else { - report_fatal_error( - "This constant type is not supported yet in constantpool"); - } - - OutStreamer->emitRawText(StringRef(LiteralStr.str())); + auto *TS = + static_cast(OutStreamer->getTargetStreamer()); + const Constant *C = CPE.Val.ConstVal; + const MCExpr *Value = nullptr; + + Type *Ty = C->getType(); + if (const auto *CFP = dyn_cast(C)) { + Value = MCConstantExpr::create( + CFP->getValueAPF().bitcastToAPInt().getSExtValue(), OutContext); + } else if (const auto *CI = dyn_cast(C)) { + Value = MCConstantExpr::create(CI->getValue().getSExtValue(), OutContext); + } else if (isa(Ty)) { + Value = lowerConstant(C); } else { - OutStreamer->emitCodeAlignment( - Align(4), OutStreamer->getContext().getSubtargetInfo()); - OutStreamer->emitLabel(LblSym); - emitGlobalConstant(getDataLayout(), CPE.Val.ConstVal); + llvm_unreachable("unexpected constant pool entry type"); } + + TS->emitLiteral(LblSym, Value, false); } } @@ -137,41 +119,19 @@ void XtensaAsmPrinter::emitConstantPool() { if (CP.empty()) return; - if (OutStreamer->hasRawTextSupport()) { - OutStreamer->switchSection(getObjFileLowering().SectionForGlobal(&F, TM)); - OutStreamer->emitRawText(StringRef("\t.literal_position\n")); - } else { - MCSectionELF *CS = - (MCSectionELF *)getObjFileLowering().SectionForGlobal(&F, TM); - StringRef CSectionName = CS->getName(); - std::size_t Pos = CSectionName.find(".text"); - std::string SectionName; - if (Pos != std::string::npos) { - SectionName = CSectionName.substr(0, Pos); - - if (Pos > 0) - SectionName += ".text"; - - CSectionName = CSectionName.drop_front(Pos); - CSectionName.consume_front(".text"); - - SectionName += ".literal"; - SectionName += CSectionName; - } else { - SectionName = CSectionName; - SectionName += ".literal"; - } + OutStreamer->pushSection(); - MCSectionELF *S = OutContext.getELFSection( - SectionName, ELF::SHT_PROGBITS, ELF::SHF_EXECINSTR | ELF::SHF_ALLOC); - S->setAlignment(Align(4)); - OutStreamer->switchSection(S); - } + auto *TS = + static_cast(OutStreamer->getTargetStreamer()); + MCSection *CS = getObjFileLowering().SectionForGlobal(&F, TM); + TS->startLiteralSection(CS); int CPIdx = 0; for (const MachineConstantPoolEntry &CPE : CP) { emitMachineConstantPoolEntry(CPE, CPIdx++); } + + OutStreamer->popSection(); } MCSymbol * diff --git a/llvm/lib/Target/Xtensa/XtensaConstantPoolValue.cpp b/llvm/lib/Target/Xtensa/XtensaConstantPoolValue.cpp index 902b29c4e767a..4e53aa5736c72 100644 --- a/llvm/lib/Target/Xtensa/XtensaConstantPoolValue.cpp +++ b/llvm/lib/Target/Xtensa/XtensaConstantPoolValue.cpp @@ -22,16 +22,16 @@ using namespace llvm; XtensaConstantPoolValue::XtensaConstantPoolValue( - Type *Ty, unsigned id, XtensaCP::XtensaCPKind kind, + Type *Ty, unsigned ID, XtensaCP::XtensaCPKind Kind, XtensaCP::XtensaCPModifier modifier) - : MachineConstantPoolValue(Ty), LabelId(id), Kind(kind), + : MachineConstantPoolValue(Ty), LabelId(ID), Kind(Kind), Modifier(modifier) {} XtensaConstantPoolValue::XtensaConstantPoolValue( - LLVMContext &C, unsigned id, XtensaCP::XtensaCPKind kind, - XtensaCP::XtensaCPModifier modifier) - : MachineConstantPoolValue((Type *)Type::getInt32Ty(C)), LabelId(id), - Kind(kind), Modifier(modifier) {} + LLVMContext &C, unsigned ID, XtensaCP::XtensaCPKind Kind, + XtensaCP::XtensaCPModifier Modifier) + : MachineConstantPoolValue((Type *)Type::getInt32Ty(C)), LabelId(ID), + Kind(Kind), Modifier(Modifier) {} XtensaConstantPoolValue::~XtensaConstantPoolValue() {} @@ -62,7 +62,9 @@ bool XtensaConstantPoolValue::hasSameValue(XtensaConstantPoolValue *ACPV) { return false; } +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) void XtensaConstantPoolValue::dump() const { errs() << " " << *this; } +#endif void XtensaConstantPoolValue::print(raw_ostream &O) const {} @@ -72,7 +74,7 @@ void XtensaConstantPoolValue::print(raw_ostream &O) const {} XtensaConstantPoolConstant::XtensaConstantPoolConstant( const Constant *C, unsigned ID, XtensaCP::XtensaCPKind Kind) - : XtensaConstantPoolValue((Type *)C->getType(), ID, Kind), CVal(C) {} + : XtensaConstantPoolValue(C->getType(), ID, Kind), CVal(C) {} XtensaConstantPoolConstant * XtensaConstantPoolConstant::Create(const Constant *C, unsigned ID, @@ -108,18 +110,18 @@ void XtensaConstantPoolConstant::print(raw_ostream &O) const { } XtensaConstantPoolSymbol::XtensaConstantPoolSymbol( - LLVMContext &C, const char *s, unsigned id, bool PrivLinkage, + LLVMContext &C, const char *Str, unsigned ID, bool PrivLinkage, XtensaCP::XtensaCPModifier Modifier) - : XtensaConstantPoolValue(C, id, XtensaCP::CPExtSymbol, Modifier), S(s), + : XtensaConstantPoolValue(C, ID, XtensaCP::CPExtSymbol, Modifier), S(Str), PrivateLinkage(PrivLinkage) {} XtensaConstantPoolSymbol * -XtensaConstantPoolSymbol::Create(LLVMContext &C, const char *s, unsigned ID, +XtensaConstantPoolSymbol::Create(LLVMContext &C, const char *Str, unsigned ID, bool PrivLinkage, XtensaCP::XtensaCPModifier Modifier) { - return new XtensaConstantPoolSymbol(C, s, ID, PrivLinkage, Modifier); + return new XtensaConstantPoolSymbol(C, Str, ID, PrivLinkage, Modifier); } int XtensaConstantPoolSymbol::getExistingMachineCPValue(MachineConstantPool *CP, @@ -144,14 +146,14 @@ void XtensaConstantPoolSymbol::print(raw_ostream &O) const { } XtensaConstantPoolMBB::XtensaConstantPoolMBB(LLVMContext &C, - const MachineBasicBlock *mbb, - unsigned id) - : XtensaConstantPoolValue(C, 0, XtensaCP::CPMachineBasicBlock), MBB(mbb) {} + const MachineBasicBlock *M, + unsigned Id) + : XtensaConstantPoolValue(C, 0, XtensaCP::CPMachineBasicBlock), MBB(M) {} -XtensaConstantPoolMBB * -XtensaConstantPoolMBB::Create(LLVMContext &C, const MachineBasicBlock *mbb, - unsigned idx) { - return new XtensaConstantPoolMBB(C, mbb, idx); +XtensaConstantPoolMBB *XtensaConstantPoolMBB::Create(LLVMContext &C, + const MachineBasicBlock *M, + unsigned Idx) { + return new XtensaConstantPoolMBB(C, M, Idx); } int XtensaConstantPoolMBB::getExistingMachineCPValue(MachineConstantPool *CP, @@ -176,12 +178,12 @@ void XtensaConstantPoolMBB::print(raw_ostream &O) const { } XtensaConstantPoolJumpTable::XtensaConstantPoolJumpTable(LLVMContext &C, - unsigned idx) - : XtensaConstantPoolValue(C, 0, XtensaCP::CPJumpTable), IDX(idx) {} + unsigned Index) + : XtensaConstantPoolValue(C, 0, XtensaCP::CPJumpTable), Idx(Index) {} XtensaConstantPoolJumpTable *XtensaConstantPoolJumpTable::Create(LLVMContext &C, - unsigned idx) { - return new XtensaConstantPoolJumpTable(C, idx); + unsigned Idx) { + return new XtensaConstantPoolJumpTable(C, Idx); } int XtensaConstantPoolJumpTable::getExistingMachineCPValue( @@ -193,13 +195,13 @@ int XtensaConstantPoolJumpTable::getExistingMachineCPValue( bool XtensaConstantPoolJumpTable::hasSameValue(XtensaConstantPoolValue *ACPV) { const XtensaConstantPoolJumpTable *ACPJT = dyn_cast(ACPV); - return ACPJT && ACPJT->IDX == IDX && + return ACPJT && ACPJT->Idx == Idx && XtensaConstantPoolValue::hasSameValue(ACPV); } void XtensaConstantPoolJumpTable::addSelectionDAGCSEId(FoldingSetNodeID &ID) {} void XtensaConstantPoolJumpTable::print(raw_ostream &O) const { - O << "JT" << IDX; + O << "JT" << Idx; XtensaConstantPoolValue::print(O); } diff --git a/llvm/lib/Target/Xtensa/XtensaConstantPoolValue.h b/llvm/lib/Target/Xtensa/XtensaConstantPoolValue.h index 8c80b0e0dbb44..5580de4844746 100644 --- a/llvm/lib/Target/Xtensa/XtensaConstantPoolValue.h +++ b/llvm/lib/Target/Xtensa/XtensaConstantPoolValue.h @@ -53,7 +53,7 @@ class XtensaConstantPoolValue : public MachineConstantPoolValue { protected: XtensaConstantPoolValue( - Type *Ty, unsigned id, XtensaCP::XtensaCPKind Kind, + Type *Ty, unsigned ID, XtensaCP::XtensaCPKind Kind, XtensaCP::XtensaCPModifier Modifier = XtensaCP::no_modifier); XtensaConstantPoolValue( @@ -66,8 +66,8 @@ class XtensaConstantPoolValue : public MachineConstantPoolValue { for (unsigned i = 0, e = Constants.size(); i != e; ++i) { if (Constants[i].isMachineConstantPoolEntry() && (Constants[i].getAlign() >= Alignment)) { - XtensaConstantPoolValue *CPV = - (XtensaConstantPoolValue *)Constants[i].Val.MachineCPVal; + auto *CPV = static_cast( + Constants[i].Val.MachineCPVal); if (Derived *APC = dyn_cast(CPV)) if (cast(this)->equals(APC)) return i; @@ -85,7 +85,7 @@ class XtensaConstantPoolValue : public MachineConstantPoolValue { StringRef getModifierText() const; unsigned getLabelId() const { return LabelId; } - void setLabelId(unsigned id) { LabelId = id; } + void setLabelId(unsigned ID) { LabelId = ID; } bool isExtSymbol() const { return Kind == XtensaCP::CPExtSymbol; } bool isBlockAddress() const { return Kind == XtensaCP::CPBlockAddress; } @@ -108,11 +108,10 @@ class XtensaConstantPoolValue : public MachineConstantPoolValue { } void print(raw_ostream &O) const override; - void print(raw_ostream *O) const { - if (O) - print(*O); - } + +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) void dump() const; +#endif }; inline raw_ostream &operator<<(raw_ostream &O, @@ -161,12 +160,12 @@ class XtensaConstantPoolSymbol : public XtensaConstantPoolValue { bool PrivateLinkage; XtensaConstantPoolSymbol( - LLVMContext &C, const char *s, unsigned id, bool PrivLinkage, + LLVMContext &C, const char *S, unsigned Id, bool PrivLinkage, XtensaCP::XtensaCPModifier Modifier = XtensaCP::no_modifier); public: static XtensaConstantPoolSymbol * - Create(LLVMContext &C, const char *s, unsigned ID, bool PrivLinkage, + Create(LLVMContext &C, const char *S, unsigned ID, bool PrivLinkage, XtensaCP::XtensaCPModifier Modifier = XtensaCP::no_modifier); const char *getSymbol() const { return S.c_str(); } @@ -198,12 +197,12 @@ class XtensaConstantPoolSymbol : public XtensaConstantPoolValue { class XtensaConstantPoolMBB : public XtensaConstantPoolValue { const MachineBasicBlock *MBB; // Machine basic block. - XtensaConstantPoolMBB(LLVMContext &C, const MachineBasicBlock *mbb, - unsigned id); + XtensaConstantPoolMBB(LLVMContext &C, const MachineBasicBlock *M, + unsigned ID); public: - static XtensaConstantPoolMBB * - Create(LLVMContext &C, const MachineBasicBlock *mbb, unsigned ID); + static XtensaConstantPoolMBB *Create(LLVMContext &C, + const MachineBasicBlock *M, unsigned ID); const MachineBasicBlock *getMBB() const { return MBB; } @@ -230,14 +229,14 @@ class XtensaConstantPoolMBB : public XtensaConstantPoolValue { /// XtensaConstantPoolJumpTable - Xtensa-specific constantpool values for Jump /// Table symbols. class XtensaConstantPoolJumpTable : public XtensaConstantPoolValue { - unsigned IDX; // Jump Table Index. + unsigned Idx; // Jump Table Index. - XtensaConstantPoolJumpTable(LLVMContext &C, unsigned idx); + XtensaConstantPoolJumpTable(LLVMContext &C, unsigned Idx); public: - static XtensaConstantPoolJumpTable *Create(LLVMContext &C, unsigned idx); + static XtensaConstantPoolJumpTable *Create(LLVMContext &C, unsigned Idx); - unsigned getIndex() const { return IDX; } + unsigned getIndex() const { return Idx; } int getExistingMachineCPValue(MachineConstantPool *CP, Align Alignment) override; @@ -255,7 +254,7 @@ class XtensaConstantPoolJumpTable : public XtensaConstantPoolValue { } bool equals(const XtensaConstantPoolJumpTable *A) const { - return IDX == A->IDX && XtensaConstantPoolValue::equals(A); + return Idx == A->Idx && XtensaConstantPoolValue::equals(A); } }; diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp b/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp index 2c3d237c97296..26d8727ce1d3b 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.cpp @@ -24,7 +24,7 @@ using namespace llvm; -static inline const MachineInstrBuilder & +static const MachineInstrBuilder & addFrameReference(const MachineInstrBuilder &MIB, int FI) { MachineInstr *MI = MIB; MachineFunction &MF = *MI->getParent()->getParent(); @@ -63,9 +63,9 @@ void XtensaInstrInfo::adjustStackPtr(unsigned SP, int64_t Amount, // create virtual reg to store immediate unsigned Reg = RegInfo.createVirtualRegister(RC); - if (isInt<8>(Amount)) // addi sp, sp, amount + if (isInt<8>(Amount)) { // addi sp, sp, amount BuildMI(MBB, I, DL, get(Xtensa::ADDI), Reg).addReg(SP).addImm(Amount); - else { // Expand immediate that doesn't fit in 12-bit. + } else { // Expand immediate that doesn't fit in 8-bit. unsigned Reg1; loadImmediate(MBB, I, &Reg1, Amount); BuildMI(MBB, I, DL, get(Xtensa::ADD), Reg) diff --git a/llvm/test/MC/Xtensa/invalid-literal.s b/llvm/test/MC/Xtensa/invalid-literal.s new file mode 100644 index 0000000000000..ebb37441059ca --- /dev/null +++ b/llvm/test/MC/Xtensa/invalid-literal.s @@ -0,0 +1,10 @@ +# RUN: not llvm-mc %s -triple=xtensa -filetype=asm 2>&1 | FileCheck %s + +.text +.literal_position +.literal .LCPI0_0 a +# CHECK: [[@LINE-1]]:20: error: expected comma +.literal 123, a +# CHECK: [[@LINE-1]]:10: error: literal label must be a symbol +.literal .LCPI1_0, +# CHECK: [[@LINE-1]]:19: error: expected value From b2f202c63c9c063266cc8bf898e79763a302a7cb Mon Sep 17 00:00:00 2001 From: Andrei Safronov Date: Thu, 11 Apr 2024 11:08:38 +0300 Subject: [PATCH 6/6] [Xtensa] Minor fixes. --- llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp index 009dbb1794569..64b996b6a42e5 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp @@ -23,6 +23,7 @@ #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 @@ -128,7 +129,7 @@ static bool CC_Xtensa_Custom(unsigned ValNo, MVT ValVT, MVT LocVT, bool needs64BitAlign = (ValVT == MVT::i32 && OrigAlign == Align(8)); bool needs128BitAlign = (ValVT == MVT::i32 && OrigAlign == Align(16)); - if (ValVT == MVT::i32 || ValVT == MVT::f32) { + 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. @@ -290,7 +291,7 @@ XtensaTargetLowering::LowerCall(CallLoweringInfo &CLI, // Get a count of how many bytes are to be pushed on the stack. unsigned NumBytes = CCInfo.getStackSize(); - unsigned StackAlignment = TFL->getStackAlignment(); + Align StackAlignment = TFL->getStackAlign(); unsigned NextStackOffset = alignTo(NumBytes, StackAlignment); Chain = DAG.getCALLSEQ_START(Chain, NextStackOffset, 0, DL); @@ -493,19 +494,19 @@ 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(); + 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) + 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) && - (value >= -32768) && (value <= 32512) && ((value & 0xff) == 0)) + isShiftedInt<16, 8>(Value)) return Op; Type *Ty = Type::getInt32Ty(*DAG.getContext()); - Constant *CV = ConstantInt::get(Ty, value); + Constant *CV = ConstantInt::get(Ty, Value); SDValue CP = DAG.getConstantPool(CV, MVT::i32); return CP; }