diff --git a/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp b/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp index e222919b28dc9..3f99387f759d9 100644 --- a/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp +++ b/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp @@ -22,6 +22,7 @@ #include "llvm/CodeGen/MachineModuleInfoImpls.h" #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" #include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInstBuilder.h" #include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" @@ -42,9 +43,20 @@ getModifierVariantKind(XtensaCP::XtensaCPModifier Modifier) { } void XtensaAsmPrinter::emitInstruction(const MachineInstr *MI) { - MCInst LoweredMI; - lowerToMCInst(MI, LoweredMI); - EmitToStreamer(*OutStreamer, LoweredMI); + unsigned Opc = MI->getOpcode(); + + switch (Opc) { + case Xtensa::BR_JT: + EmitToStreamer( + *OutStreamer, + MCInstBuilder(Xtensa::JX).addReg(MI->getOperand(0).getReg())); + return; + default: + MCInst LoweredMI; + lowerToMCInst(MI, LoweredMI); + EmitToStreamer(*OutStreamer, LoweredMI); + return; + } } void XtensaAsmPrinter::emitMachineConstantPoolValue( @@ -52,16 +64,27 @@ void XtensaAsmPrinter::emitMachineConstantPoolValue( 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; + if (ACPV->isBlockAddress()) { + const BlockAddress *BA = + cast(ACPV)->getBlockAddress(); + MCSym = GetBlockAddressSymbol(BA); + } else if (ACPV->isJumpTable()) { + unsigned Idx = cast(ACPV)->getIndex(); + MCSym = this->GetJTISymbol(Idx, false); + } else { + assert(ACPV->isExtSymbol() && "unrecognized constant pool value"); + XtensaConstantPoolSymbol *XtensaSym = cast(ACPV); + const char *SymName = XtensaSym->getSymbol(); + + if (XtensaSym->isPrivateLinkage()) { + const DataLayout &DL = getDataLayout(); + MCSym = OutContext.getOrCreateSymbol(Twine(DL.getPrivateGlobalPrefix()) + + SymName); + } else { + MCSym = OutContext.getOrCreateSymbol(SymName); + } + } - MCSym = GetExternalSymbolSymbol(StringRef(SymName)); MCSymbol *LblSym = GetCPISymbol(ACPV->getLabelId()); auto *TS = static_cast(OutStreamer->getTargetStreamer()); @@ -71,7 +94,7 @@ void XtensaAsmPrinter::emitMachineConstantPoolValue( std::string SymName(MCSym->getName()); StringRef Modifier = ACPV->getModifierText(); SymName += Modifier; - MCSym = GetExternalSymbolSymbol(StringRef(SymName)); + MCSym = OutContext.getOrCreateSymbol(SymName); } const MCExpr *Expr = MCSymbolRefExpr::create(MCSym, VK, OutContext); @@ -140,6 +163,10 @@ XtensaAsmPrinter::GetConstantPoolIndexSymbol(const MachineOperand &MO) const { return GetCPISymbol(MO.getIndex()); } +MCSymbol *XtensaAsmPrinter::GetJumpTableSymbol(const MachineOperand &MO) const { + return GetJTISymbol(MO.getIndex()); +} + MCOperand XtensaAsmPrinter::LowerSymbolOperand(const MachineOperand &MO, MachineOperand::MachineOperandType MOTy, @@ -152,6 +179,20 @@ XtensaAsmPrinter::LowerSymbolOperand(const MachineOperand &MO, Symbol = getSymbol(MO.getGlobal()); Offset += MO.getOffset(); break; + case MachineOperand::MO_MachineBasicBlock: + Symbol = MO.getMBB()->getSymbol(); + break; + case MachineOperand::MO_BlockAddress: + Symbol = GetBlockAddressSymbol(MO.getBlockAddress()); + Offset += MO.getOffset(); + break; + case MachineOperand::MO_ExternalSymbol: + Symbol = GetExternalSymbolSymbol(MO.getSymbolName()); + Offset += MO.getOffset(); + break; + case MachineOperand::MO_JumpTableIndex: + Symbol = GetJumpTableSymbol(MO); + break; case MachineOperand::MO_ConstantPoolIndex: Symbol = GetConstantPoolIndexSymbol(MO); Offset += MO.getOffset(); @@ -191,6 +232,10 @@ MCOperand XtensaAsmPrinter::lowerOperand(const MachineOperand &MO, case MachineOperand::MO_RegisterMask: break; case MachineOperand::MO_GlobalAddress: + case MachineOperand::MO_MachineBasicBlock: + case MachineOperand::MO_BlockAddress: + case MachineOperand::MO_ExternalSymbol: + case MachineOperand::MO_JumpTableIndex: case MachineOperand::MO_ConstantPoolIndex: return LowerSymbolOperand(MO, MOTy, Offset); default: diff --git a/llvm/lib/Target/Xtensa/XtensaAsmPrinter.h b/llvm/lib/Target/Xtensa/XtensaAsmPrinter.h index f3fec19724aab..f9cf5ae8c9f65 100644 --- a/llvm/lib/Target/Xtensa/XtensaAsmPrinter.h +++ b/llvm/lib/Target/Xtensa/XtensaAsmPrinter.h @@ -44,6 +44,8 @@ class LLVM_LIBRARY_VISIBILITY XtensaAsmPrinter : public AsmPrinter { MCSymbol *GetConstantPoolIndexSymbol(const MachineOperand &MO) const; + MCSymbol *GetJumpTableSymbol(const MachineOperand &MO) const; + MCOperand LowerSymbolOperand(const MachineOperand &MO, MachineOperand::MachineOperandType MOTy, unsigned Offset) const; diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp index 6c3258b4bb46c..6509793012504 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp @@ -77,6 +77,18 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &TM, } setOperationAction(ISD::ConstantPool, PtrVT, Custom); + setOperationAction(ISD::GlobalAddress, PtrVT, Custom); + setOperationAction(ISD::BlockAddress, PtrVT, Custom); + setOperationAction(ISD::JumpTable, PtrVT, Custom); + + // Expand jump table branches as address arithmetic followed by an + // indirect jump. + setOperationAction(ISD::BR_JT, MVT::Other, Custom); + + setOperationPromotedToType(ISD::BR_CC, MVT::i1, MVT::i32); + setOperationAction(ISD::BR_CC, MVT::i32, Legal); + setOperationAction(ISD::BR_CC, MVT::i64, Expand); + setOperationAction(ISD::BR_CC, MVT::f32, Expand); // Implement custom stack allocations setOperationAction(ISD::DYNAMIC_STACKALLOC, PtrVT, Custom); @@ -88,6 +100,12 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &TM, computeRegisterProperties(STI.getRegisterInfo()); } +bool XtensaTargetLowering::isOffsetFoldingLegal( + const GlobalAddressSDNode *GA) const { + // The Xtensa target isn't yet aware of offsets. + return false; +} + //===----------------------------------------------------------------------===// // Calling conventions //===----------------------------------------------------------------------===// @@ -519,6 +537,72 @@ SDValue XtensaTargetLowering::LowerImmediate(SDValue Op, return Op; } +SDValue XtensaTargetLowering::LowerGlobalAddress(SDValue Op, + SelectionDAG &DAG) const { + const GlobalAddressSDNode *G = cast(Op); + SDLoc DL(Op); + auto PtrVT = Op.getValueType(); + const GlobalValue *GV = G->getGlobal(); + + SDValue CPAddr = DAG.getTargetConstantPool(GV, PtrVT, Align(4)); + SDValue CPWrap = getAddrPCRel(CPAddr, DAG); + + return CPWrap; +} + +SDValue XtensaTargetLowering::LowerBlockAddress(SDValue Op, + SelectionDAG &DAG) const { + BlockAddressSDNode *Node = cast(Op); + const BlockAddress *BA = Node->getBlockAddress(); + EVT PtrVT = Op.getValueType(); + + XtensaConstantPoolValue *CPV = + XtensaConstantPoolConstant::Create(BA, 0, XtensaCP::CPBlockAddress); + SDValue CPAddr = DAG.getTargetConstantPool(CPV, PtrVT, Align(4)); + SDValue CPWrap = getAddrPCRel(CPAddr, DAG); + + return CPWrap; +} + +SDValue XtensaTargetLowering::LowerBR_JT(SDValue Op, SelectionDAG &DAG) const { + SDValue Chain = Op.getOperand(0); + SDValue Table = Op.getOperand(1); + SDValue Index = Op.getOperand(2); + SDLoc DL(Op); + JumpTableSDNode *JT = cast(Table); + MachineFunction &MF = DAG.getMachineFunction(); + const MachineJumpTableInfo *MJTI = MF.getJumpTableInfo(); + SDValue TargetJT = DAG.getTargetJumpTable(JT->getIndex(), MVT::i32); + const DataLayout &TD = DAG.getDataLayout(); + EVT PtrVT = Table.getValueType(); + unsigned EntrySize = MJTI->getEntrySize(TD); + + Index = DAG.getNode(ISD::MUL, DL, Index.getValueType(), Index, + DAG.getConstant(EntrySize, DL, Index.getValueType())); + SDValue Addr = DAG.getNode(ISD::ADD, DL, Index.getValueType(), Index, Table); + SDValue LD = + DAG.getLoad(PtrVT, DL, Chain, Addr, + MachinePointerInfo::getJumpTable(DAG.getMachineFunction())); + + return DAG.getNode(XtensaISD::BR_JT, DL, MVT::Other, LD.getValue(1), LD, + TargetJT); +} + +SDValue XtensaTargetLowering::LowerJumpTable(SDValue Op, + SelectionDAG &DAG) const { + JumpTableSDNode *JT = cast(Op); + EVT PtrVT = Op.getValueType(); + + // Create a constant pool entry for the callee address + XtensaConstantPoolValue *CPV = + XtensaConstantPoolJumpTable::Create(*DAG.getContext(), JT->getIndex()); + + // Get the address of the callee into a register + SDValue CPAddr = DAG.getTargetConstantPool(CPV, PtrVT, Align(4)); + + return getAddrPCRel(CPAddr, DAG); +} + SDValue XtensaTargetLowering::getAddrPCRel(SDValue Op, SelectionDAG &DAG) const { SDLoc DL(Op); @@ -580,8 +664,16 @@ SDValue XtensaTargetLowering::LowerDYNAMIC_STACKALLOC(SDValue Op, SDValue XtensaTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const { switch (Op.getOpcode()) { + case ISD::BR_JT: + return LowerBR_JT(Op, DAG); case ISD::Constant: return LowerImmediate(Op, DAG); + case ISD::GlobalAddress: + return LowerGlobalAddress(Op, DAG); + case ISD::BlockAddress: + return LowerBlockAddress(Op, DAG); + case ISD::JumpTable: + return LowerJumpTable(Op, DAG); case ISD::ConstantPool: return LowerConstantPool(cast(Op), DAG); case ISD::STACKSAVE: @@ -597,6 +689,8 @@ SDValue XtensaTargetLowering::LowerOperation(SDValue Op, const char *XtensaTargetLowering::getTargetNodeName(unsigned Opcode) const { switch (Opcode) { + case XtensaISD::BR_JT: + return "XtensaISD::BR_JT"; case XtensaISD::CALL: return "XtensaISD::CALL"; case XtensaISD::PCREL_WRAPPER: diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.h b/llvm/lib/Target/Xtensa/XtensaISelLowering.h index 6f6ec391430a9..23a0217daaa96 100644 --- a/llvm/lib/Target/Xtensa/XtensaISelLowering.h +++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.h @@ -23,6 +23,7 @@ namespace llvm { namespace XtensaISD { enum { FIRST_NUMBER = ISD::BUILTIN_OP_END, + BR_JT, // Calls a function. Operand 0 is the chain operand and operand 1 // is the target address. The arguments start at operand 2. @@ -43,6 +44,8 @@ class XtensaTargetLowering : public TargetLowering { explicit XtensaTargetLowering(const TargetMachine &TM, const XtensaSubtarget &STI); + bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const override; + const char *getTargetNodeName(unsigned Opcode) const override; SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override; @@ -71,8 +74,16 @@ class XtensaTargetLowering : public TargetLowering { private: const XtensaSubtarget &Subtarget; + SDValue LowerBR_JT(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerImmediate(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const; + + SDValue LowerBlockAddress(SDValue Op, SelectionDAG &DAG) const; + + SDValue LowerJumpTable(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerConstantPool(ConstantPoolSDNode *CP, SelectionDAG &DAG) const; SDValue LowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG) const; diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td index 6e9e75257ccf4..f68d20dcdd54a 100644 --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td @@ -416,6 +416,15 @@ def BBSI : RRI8_Inst<0x07, (outs), let imm8 = target; } +def : Pat<(brcc SETGT, AR:$s, AR:$t, bb:$target), + (BLT AR:$t, AR:$s, bb:$target)>; +def : Pat<(brcc SETUGT, AR:$s, AR:$t, bb:$target), + (BLTU AR:$t, AR:$s, bb:$target)>; +def : Pat<(brcc SETLE, AR:$s, AR:$t, bb:$target), + (BGE AR:$t, AR:$s, bb:$target)>; +def : Pat<(brcc SETULE, AR:$s, AR:$t, bb:$target), + (BGEU AR:$t, AR:$s, bb:$target)>; + //===----------------------------------------------------------------------===// // Call and jump instructions //===----------------------------------------------------------------------===// @@ -471,6 +480,12 @@ def : Pat<(Xtensa_call (i32 texternalsym:$dst)), def : Pat<(Xtensa_call AR:$dst), (CALLX0 AR:$dst)>; +let isBranch = 1, isTerminator = 1, isBarrier = 1, isIndirectBranch = 1, Size = 3 in { + def BR_JT: Pseudo<(outs), (ins AR:$s, i32imm:$jt), + "!br_jt_p, $s, $jt", + [(Xtensa_brjt AR:$s, tjumptable:$jt)]>; +} + //===----------------------------------------------------------------------===// // Mem barrier instructions //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/Xtensa/XtensaOperators.td b/llvm/lib/Target/Xtensa/XtensaOperators.td index cd4d831c85b58..88d3c9dfe7fd8 100644 --- a/llvm/lib/Target/Xtensa/XtensaOperators.td +++ b/llvm/lib/Target/Xtensa/XtensaOperators.td @@ -17,6 +17,8 @@ def SDT_XtensaWrapPtr : SDTypeProfile<1, 1, [SDTCisSameAs<0, 1>, SDTCisPtrTy<0>]>; +def SDT_XtensaBrJT : SDTypeProfile<0, 2, + [SDTCisPtrTy<0>, SDTCisVT<1, i32>]>; //===----------------------------------------------------------------------===// // Node definitions //===----------------------------------------------------------------------===// @@ -34,3 +36,5 @@ def Xtensa_callseq_start: SDNode<"ISD::CALLSEQ_START", SDT_XtensaCallSeqStart, def Xtensa_callseq_end : SDNode<"ISD::CALLSEQ_END", SDT_XtensaCallSeqEnd, [SDNPHasChain, SDNPSideEffect, SDNPOptInGlue, SDNPOutGlue]>; + +def Xtensa_brjt: SDNode<"XtensaISD::BR_JT", SDT_XtensaBrJT, [SDNPHasChain]>; diff --git a/llvm/test/CodeGen/Xtensa/blockaddress.ll b/llvm/test/CodeGen/Xtensa/blockaddress.ll new file mode 100644 index 0000000000000..bbeb1790a1b78 --- /dev/null +++ b/llvm/test/CodeGen/Xtensa/blockaddress.ll @@ -0,0 +1,26 @@ +; RUN: llc --mtriple=xtensa < %s | FileCheck %s + +@addr = global ptr null + +define void @test_blockaddress() { + + store volatile ptr blockaddress(@test_blockaddress, %block), ptr @addr +; CHECK: .literal_position +; CHECK-NEXT: .literal .LCPI0_0, addr +; CHECK-NEXT: .literal .LCPI0_1, .Ltmp0 +; CHECK-LABEL: test_blockaddress: +; CHECK: # %bb.0: +; CHECK-NEXT: l32r a8, .LCPI0_0 +; CHECK-NEXT: l32r a9, .LCPI0_1 +; CHECK-NEXT: s32i a9, a8, 0 +; CHECK-NEXT: l32i a8, a8, 0 +; CHECK-NEXT: jx a8 +; CHECK-NEXT: .Ltmp0: +; CHECK-NEXT: .LBB0_1: + + %val = load volatile ptr, ptr @addr + indirectbr ptr %val, [label %block] + +block: + ret void +} diff --git a/llvm/test/CodeGen/Xtensa/brcc.ll b/llvm/test/CodeGen/Xtensa/brcc.ll new file mode 100644 index 0000000000000..83f6dfd1aebc3 --- /dev/null +++ b/llvm/test/CodeGen/Xtensa/brcc.ll @@ -0,0 +1,77 @@ +; RUN: llc -march=xtensa < %s | FileCheck %s + +; CHECK-LABEL: brcc1: +; CHECK: bge a3, a2, .LBB0_2 +; CHECK: addi a2, a2, 4 +; CHECK: .LBB0_2: +define i32 @brcc1(i32 %a, i32 %b) nounwind { +entry: + %wb = icmp sgt i32 %a, %b + br i1 %wb, label %t1, label %t2 +t1: + %t1v = add i32 %a, 4 + br label %exit +t2: + %t2v = add i32 %b, 8 + br label %exit +exit: + %v = phi i32 [ %t1v, %t1 ], [ %t2v, %t2 ] + ret i32 %v +} + +; CHECK-LABEL: brcc2 +; CHECK: bgeu a3, a2, .LBB1_2 +; CHECK: addi a2, a2, 4 +; CHECK: .LBB1_2: +define i32 @brcc2(i32 %a, i32 %b) nounwind { +entry: + %wb = icmp ugt i32 %a, %b + br i1 %wb, label %t1, label %t2 +t1: + %t1v = add i32 %a, 4 + br label %exit +t2: + %t2v = add i32 %b, 8 + br label %exit +exit: + %v = phi i32 [ %t1v, %t1 ], [ %t2v, %t2 ] + ret i32 %v +} + +; CHECK-LABEL: brcc3: +; CHECK: blt a3, a2, .LBB2_2 +; CHECK: addi a2, a2, 4 +; CHECK: .LBB2_2: +define i32 @brcc3(i32 %a, i32 %b) nounwind { +entry: + %wb = icmp sle i32 %a, %b + br i1 %wb, label %t1, label %t2 +t1: + %t1v = add i32 %a, 4 + br label %exit +t2: + %t2v = add i32 %b, 8 + br label %exit +exit: + %v = phi i32 [ %t1v, %t1 ], [ %t2v, %t2 ] + ret i32 %v +} + +; CHECK-LABEL: brcc4 +; CHECK: bltu a3, a2, .LBB3_2 +; CHECK: addi a2, a2, 4 +; CHECK: .LBB3_2: +define i32 @brcc4(i32 %a, i32 %b) nounwind { +entry: + %wb = icmp ule i32 %a, %b + br i1 %wb, label %t1, label %t2 +t1: + %t1v = add i32 %a, 4 + br label %exit +t2: + %t2v = add i32 %b, 8 + br label %exit +exit: + %v = phi i32 [ %t1v, %t1 ], [ %t2v, %t2 ] + ret i32 %v +} diff --git a/llvm/test/CodeGen/Xtensa/indirectbr.ll b/llvm/test/CodeGen/Xtensa/indirectbr.ll new file mode 100644 index 0000000000000..c4181c28826f4 --- /dev/null +++ b/llvm/test/CodeGen/Xtensa/indirectbr.ll @@ -0,0 +1,32 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 2 +; RUN: llc -mtriple=xtensa -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=XTENSA %s + +define i32 @indirectbr(i8* %target) nounwind { +; XTENSA-LABEL: indirectbr: +; XTENSA: jx a2 +; XTENSA-NEXT: .LBB0_1: # %test_label +; XTENSA-NEXT: movi a2, 0 +; XTENSA-NEXT: ret + indirectbr i8* %target, [label %test_label] +test_label: + br label %ret +ret: + ret i32 0 +} + +define i32 @indirectbr_with_offset(i8* %a) nounwind { +; XTENSA-LABEL: indirectbr_with_offset: +; XTENSA: movi a8, 1380 +; XTENSA-NEXT: add a8, a2, a8 +; XTENSA-NEXT: jx a8 +; XTENSA-NEXT: .LBB1_1: # %test_label +; XTENSA-NEXT: movi a2, 0 +; XTENSA-NEXT: ret + %target = getelementptr inbounds i8, i8* %a, i32 1380 + indirectbr i8* %target, [label %test_label] +test_label: + br label %ret +ret: + ret i32 0 +} diff --git a/llvm/test/CodeGen/Xtensa/jumpt.ll b/llvm/test/CodeGen/Xtensa/jumpt.ll new file mode 100644 index 0000000000000..66c2fc39e3952 --- /dev/null +++ b/llvm/test/CodeGen/Xtensa/jumpt.ll @@ -0,0 +1,40 @@ +; RUN: llc -mtriple=xtensa -verify-machineinstrs < %s \ +; RUN: | FileCheck %s + +define void @switch_4_xtensa(i32 %in, ptr %out) nounwind { +; CHECK: .literal_position +; CHECK-NEXT: .LCPI0_0, .LJTI0_0 +; CHECK-LABEL: switch_4_xtensa: +; CHECK: # %bb.0: +; CHECK-NEXT: addi a9, a2, -1 +; CHECK-NEXT: movi a8, 3 +; CHECK-NEXT: bltu a8, a9, .LBB0_6 +; CHECK-NEXT: # %bb.1: +; CHECK-NEXT: l32r a10, .LCPI0_0 +; CHECK-NEXT: addx4 a9, a9, a10 +; CHECK-NEXT: l32i a9, a9, 0 +; CHECK-NEXT: jx a9 +; CHECK: ret + +entry: + switch i32 %in, label %exit [ + i32 1, label %bb1 + i32 2, label %bb2 + i32 3, label %bb3 + i32 4, label %bb4 + ] +bb1: + store i32 4, ptr %out + br label %exit +bb2: + store i32 3, ptr %out + br label %exit +bb3: + store i32 2, ptr %out + br label %exit +bb4: + store i32 1, ptr %out + br label %exit +exit: + ret void +}