diff --git a/llvm/lib/Target/LoongArch/CMakeLists.txt b/llvm/lib/Target/LoongArch/CMakeLists.txt --- a/llvm/lib/Target/LoongArch/CMakeLists.txt +++ b/llvm/lib/Target/LoongArch/CMakeLists.txt @@ -17,6 +17,7 @@ add_llvm_target(LoongArchCodeGen LoongArchAsmPrinter.cpp LoongArchExpandAtomicPseudoInsts.cpp + LoongArchExpandPseudoInsts.cpp LoongArchFrameLowering.cpp LoongArchInstrInfo.cpp LoongArchISelDAGToDAG.cpp diff --git a/llvm/lib/Target/LoongArch/LoongArch.h b/llvm/lib/Target/LoongArch/LoongArch.h --- a/llvm/lib/Target/LoongArch/LoongArch.h +++ b/llvm/lib/Target/LoongArch/LoongArch.h @@ -36,6 +36,9 @@ FunctionPass *createLoongArchISelDag(LoongArchTargetMachine &TM); FunctionPass *createLoongArchExpandAtomicPseudoPass(); void initializeLoongArchExpandAtomicPseudoPass(PassRegistry &); + +FunctionPass *createLoongArchPreRAExpandPseudoPass(); +void initializeLoongArchPreRAExpandPseudoPass(PassRegistry &); } // end namespace llvm #endif // LLVM_LIB_TARGET_LOONGARCH_LOONGARCH_H diff --git a/llvm/lib/Target/LoongArch/LoongArchExpandPseudoInsts.cpp b/llvm/lib/Target/LoongArch/LoongArchExpandPseudoInsts.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/LoongArch/LoongArchExpandPseudoInsts.cpp @@ -0,0 +1,162 @@ +//===-- LoongArchExpandPseudoInsts.cpp - Expand pseudo instructions -------===// +// +// 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 a pass that expands pseudo instructions into target +// instructions. +// +//===----------------------------------------------------------------------===// + +#include "LoongArch.h" +#include "LoongArchInstrInfo.h" +#include "LoongArchTargetMachine.h" +#include "MCTargetDesc/LoongArchBaseInfo.h" +#include "MCTargetDesc/LoongArchMCTargetDesc.h" +#include "llvm/CodeGen/LivePhysRegs.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/MC/MCContext.h" + +using namespace llvm; + +#define LOONGARCH_PRERA_EXPAND_PSEUDO_NAME \ + "LoongArch Pre-RA pseudo instruction expansion pass" + +namespace { + +class LoongArchPreRAExpandPseudo : public MachineFunctionPass { +public: + const LoongArchInstrInfo *TII; + static char ID; + + LoongArchPreRAExpandPseudo() : MachineFunctionPass(ID) { + initializeLoongArchPreRAExpandPseudoPass(*PassRegistry::getPassRegistry()); + } + + bool runOnMachineFunction(MachineFunction &MF) override; + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.setPreservesCFG(); + MachineFunctionPass::getAnalysisUsage(AU); + } + StringRef getPassName() const override { + return LOONGARCH_PRERA_EXPAND_PSEUDO_NAME; + } + +private: + bool expandMBB(MachineBasicBlock &MBB); + bool expandMI(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, + MachineBasicBlock::iterator &NextMBBI); + bool expandPcalau12iInstPair(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + MachineBasicBlock::iterator &NextMBBI, + unsigned FlagsHi, unsigned SecondOpcode, + unsigned FlagsLo); + bool expandLoadAddressPcrel(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + MachineBasicBlock::iterator &NextMBBI); + bool expandLoadAddressGot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + MachineBasicBlock::iterator &NextMBBI); +}; + +char LoongArchPreRAExpandPseudo::ID = 0; + +bool LoongArchPreRAExpandPseudo::runOnMachineFunction(MachineFunction &MF) { + TII = + static_cast(MF.getSubtarget().getInstrInfo()); + bool Modified = false; + for (auto &MBB : MF) + Modified |= expandMBB(MBB); + return Modified; +} + +bool LoongArchPreRAExpandPseudo::expandMBB(MachineBasicBlock &MBB) { + bool Modified = false; + + MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end(); + while (MBBI != E) { + MachineBasicBlock::iterator NMBBI = std::next(MBBI); + Modified |= expandMI(MBB, MBBI, NMBBI); + MBBI = NMBBI; + } + + return Modified; +} + +bool LoongArchPreRAExpandPseudo::expandMI( + MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, + MachineBasicBlock::iterator &NextMBBI) { + switch (MBBI->getOpcode()) { + case LoongArch::PseudoLA_PCREL: + return expandLoadAddressPcrel(MBB, MBBI, NextMBBI); + case LoongArch::PseudoLA_GOT: + return expandLoadAddressGot(MBB, MBBI, NextMBBI); + } + return false; +} + +bool LoongArchPreRAExpandPseudo::expandPcalau12iInstPair( + MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, + MachineBasicBlock::iterator &NextMBBI, unsigned FlagsHi, + unsigned SecondOpcode, unsigned FlagsLo) { + MachineFunction *MF = MBB.getParent(); + MachineInstr &MI = *MBBI; + DebugLoc DL = MI.getDebugLoc(); + + Register DestReg = MI.getOperand(0).getReg(); + Register ScratchReg = + MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass); + MachineOperand &Symbol = MI.getOperand(1); + + BuildMI(MBB, MBBI, DL, TII->get(LoongArch::PCALAU12I), ScratchReg) + .addDisp(Symbol, 0, FlagsHi); + + MachineInstr *SecondMI = + BuildMI(MBB, MBBI, DL, TII->get(SecondOpcode), DestReg) + .addReg(ScratchReg) + .addDisp(Symbol, 0, FlagsLo); + + if (MI.hasOneMemOperand()) + SecondMI->addMemOperand(*MF, *MI.memoperands_begin()); + + MI.eraseFromParent(); + return true; +} + +bool LoongArchPreRAExpandPseudo::expandLoadAddressPcrel( + MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, + MachineBasicBlock::iterator &NextMBBI) { + MachineFunction *MF = MBB.getParent(); + const auto &STI = MF->getSubtarget(); + unsigned SecondOpcode = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W; + return expandPcalau12iInstPair(MBB, MBBI, NextMBBI, LoongArchII::MO_PCREL_HI, + SecondOpcode, LoongArchII::MO_PCREL_LO); +} + +bool LoongArchPreRAExpandPseudo::expandLoadAddressGot( + MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, + MachineBasicBlock::iterator &NextMBBI) { + MachineFunction *MF = MBB.getParent(); + const auto &STI = MF->getSubtarget(); + unsigned SecondOpcode = STI.is64Bit() ? LoongArch::LD_D : LoongArch::LD_W; + return expandPcalau12iInstPair(MBB, MBBI, NextMBBI, LoongArchII::MO_GOT_PC_HI, + SecondOpcode, LoongArchII::MO_GOT_PC_LO); +} + +} // end namespace + +INITIALIZE_PASS(LoongArchPreRAExpandPseudo, "LoongArch-prera-expand-pseudo", + LOONGARCH_PRERA_EXPAND_PSEUDO_NAME, false, false) + +namespace llvm { + +FunctionPass *createLoongArchPreRAExpandPseudoPass() { + return new LoongArchPreRAExpandPseudo(); +} + +} // end namespace llvm diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.h b/llvm/lib/Target/LoongArch/LoongArchISelLowering.h --- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.h +++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.h @@ -130,7 +130,11 @@ bool IsRet, CallLoweringInfo *CLI, LoongArchCCAssignFn Fn) const; + template + SDValue getAddr(NodeTy *N, SelectionDAG &DAG, bool IsLocal = true) const; SDValue lowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerBlockAddress(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerJumpTable(SDValue Op, SelectionDAG &DAG) const; SDValue lowerShiftLeftParts(SDValue Op, SelectionDAG &DAG) const; SDValue lowerShiftRightParts(SDValue Op, SelectionDAG &DAG, bool IsSRA) const; diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp --- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp +++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp @@ -58,7 +58,9 @@ setOperationAction(ISD::ROTL, GRLenVT, Expand); setOperationAction(ISD::CTPOP, GRLenVT, Expand); - setOperationAction({ISD::GlobalAddress, ISD::ConstantPool}, GRLenVT, Custom); + setOperationAction({ISD::GlobalAddress, ISD::BlockAddress, ISD::ConstantPool, + ISD::JumpTable}, + GRLenVT, Custom); setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom); @@ -128,8 +130,6 @@ setOperationAction(ISD::FMAXNUM_IEEE, MVT::f64, Legal); } - // Effectively disable jump table generation. - setMinimumJumpTableEntries(INT_MAX); setOperationAction(ISD::BR_JT, MVT::Other, Expand); setOperationAction(ISD::BR_CC, GRLenVT, Expand); @@ -180,6 +180,10 @@ return lowerGlobalAddress(Op, DAG); case ISD::INTRINSIC_WO_CHAIN: return lowerINTRINSIC_WO_CHAIN(Op, DAG); + case ISD::BlockAddress: + return lowerBlockAddress(Op, DAG); + case ISD::JumpTable: + return lowerJumpTable(Op, DAG); case ISD::SHL_PARTS: return lowerShiftLeftParts(Op, DAG); case ISD::SRA_PARTS: @@ -272,46 +276,66 @@ return DAG.getNode(ISD::BITCAST, DL, Op.getValueType(), Trunc); } +static SDValue getTargetNode(GlobalAddressSDNode *N, SDLoc DL, EVT Ty, + SelectionDAG &DAG, unsigned Flags) { + return DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, Flags); +} + +static SDValue getTargetNode(BlockAddressSDNode *N, SDLoc DL, EVT Ty, + SelectionDAG &DAG, unsigned Flags) { + return DAG.getTargetBlockAddress(N->getBlockAddress(), Ty, N->getOffset(), + Flags); +} + +static SDValue getTargetNode(ConstantPoolSDNode *N, SDLoc DL, EVT Ty, + SelectionDAG &DAG, unsigned Flags) { + return DAG.getTargetConstantPool(N->getConstVal(), Ty, N->getAlign(), + N->getOffset(), Flags); +} + +static SDValue getTargetNode(JumpTableSDNode *N, SDLoc DL, EVT Ty, + SelectionDAG &DAG, unsigned Flags) { + return DAG.getTargetJumpTable(N->getIndex(), Ty, Flags); +} + +template +SDValue LoongArchTargetLowering::getAddr(NodeTy *N, SelectionDAG &DAG, + bool IsLocal) const { + SDLoc DL(N); + EVT Ty = getPointerTy(DAG.getDataLayout()); + SDValue Addr = getTargetNode(N, DL, Ty, DAG, 0); + // TODO: Check CodeModel. + if (IsLocal) + // This generates the pattern (PseudoLA_PCREL sym), which expands to + // (addi.w/d (pcalau12i %pc_hi20(sym)) %pc_lo12(sym)). + return SDValue(DAG.getMachineNode(LoongArch::PseudoLA_PCREL, DL, Ty, Addr), + 0); + + // This generates the pattern (PseudoLA_GOT sym), which expands to (ld.w/d + // (pcalau12i %got_pc_hi20(sym)) %got_pc_lo12(sym)). + return SDValue(DAG.getMachineNode(LoongArch::PseudoLA_GOT, DL, Ty, Addr), 0); +} + +SDValue LoongArchTargetLowering::lowerBlockAddress(SDValue Op, + SelectionDAG &DAG) const { + return getAddr(cast(Op), DAG); +} + +SDValue LoongArchTargetLowering::lowerJumpTable(SDValue Op, + SelectionDAG &DAG) const { + return getAddr(cast(Op), DAG); +} + SDValue LoongArchTargetLowering::lowerConstantPool(SDValue Op, SelectionDAG &DAG) const { - SDLoc DL(Op); - EVT Ty = Op.getValueType(); - ConstantPoolSDNode *N = cast(Op); - - // FIXME: Only support PC-relative addressing to access the symbol. - // Target flags will be added later. - if (!isPositionIndependent()) { - SDValue ConstantN = DAG.getTargetConstantPool( - N->getConstVal(), Ty, N->getAlign(), N->getOffset()); - SDValue AddrHi(DAG.getMachineNode(LoongArch::PCALAU12I, DL, Ty, ConstantN), - 0); - SDValue Addr(DAG.getMachineNode(Subtarget.is64Bit() ? LoongArch::ADDI_D - : LoongArch::ADDI_W, - DL, Ty, AddrHi, ConstantN), - 0); - return Addr; - } - report_fatal_error("Unable to lower ConstantPool"); + return getAddr(cast(Op), DAG); } SDValue LoongArchTargetLowering::lowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const { - SDLoc DL(Op); - EVT Ty = getPointerTy(DAG.getDataLayout()); - const GlobalValue *GV = cast(Op)->getGlobal(); - unsigned ADDIOp = Subtarget.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W; - - // TODO: Support dso_preemptable and target flags. - if (GV->isDSOLocal()) { - SDValue GAHi = - DAG.getTargetGlobalAddress(GV, DL, Ty, 0, LoongArchII::MO_PCREL_HI); - SDValue GALo = - DAG.getTargetGlobalAddress(GV, DL, Ty, 0, LoongArchII::MO_PCREL_LO); - SDValue AddrHi(DAG.getMachineNode(LoongArch::PCALAU12I, DL, Ty, GAHi), 0); - - return SDValue(DAG.getMachineNode(ADDIOp, DL, Ty, AddrHi, GALo), 0); - } - report_fatal_error("Unable to lowerGlobalAddress"); + GlobalAddressSDNode *N = cast(Op); + assert(N->getOffset() == 0 && "unexpected offset in global node"); + return getAddr(N, DAG, N->getGlobal()->isDSOLocal()); } SDValue LoongArchTargetLowering::lowerINTRINSIC_WO_CHAIN(SDValue Op, diff --git a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td --- a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td +++ b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td @@ -919,6 +919,12 @@ def PseudoRET : Pseudo<(outs), (ins), [(loongarch_ret)]>, PseudoInstExpansion<(JIRL R0, R1, 0)>; +let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in +def PseudoLA_PCREL : Pseudo<(outs GPR:$dst), (ins grlenimm:$src), []>; + +let hasSideEffects = 0, mayLoad = 1, mayStore = 0 in +def PseudoLA_GOT : Pseudo<(outs GPR:$dst), (ins grlenimm:$src), []>; + /// BSTRINS and BSTRPICK let Predicates = [IsLA32] in { diff --git a/llvm/lib/Target/LoongArch/LoongArchMCInstLower.cpp b/llvm/lib/Target/LoongArch/LoongArchMCInstLower.cpp --- a/llvm/lib/Target/LoongArch/LoongArchMCInstLower.cpp +++ b/llvm/lib/Target/LoongArch/LoongArchMCInstLower.cpp @@ -47,6 +47,12 @@ case LoongArchII::MO_PCREL_LO: Kind = LoongArchMCExpr::VK_LoongArch_PCALA_LO12; break; + case LoongArchII::MO_GOT_PC_HI: + Kind = LoongArchMCExpr::VK_LoongArch_GOT_HI20; + break; + case LoongArchII::MO_GOT_PC_LO: + Kind = LoongArchMCExpr::VK_LoongArch_GOT_LO12; + break; // TODO: Handle more target-flags. } @@ -94,9 +100,12 @@ MCOp = lowerSymbolOperand( MO, AP.GetExternalSymbolSymbol(MO.getSymbolName()), AP); break; - // TODO: lower special operands case MachineOperand::MO_BlockAddress: + MCOp = lowerSymbolOperand( + MO, AP.GetBlockAddressSymbol(MO.getBlockAddress()), AP); + break; case MachineOperand::MO_JumpTableIndex: + MCOp = lowerSymbolOperand(MO, AP.GetJTISymbol(MO.getIndex()), AP); break; } return true; diff --git a/llvm/lib/Target/LoongArch/LoongArchTargetMachine.cpp b/llvm/lib/Target/LoongArch/LoongArchTargetMachine.cpp --- a/llvm/lib/Target/LoongArch/LoongArchTargetMachine.cpp +++ b/llvm/lib/Target/LoongArch/LoongArchTargetMachine.cpp @@ -27,6 +27,8 @@ // Register the target. RegisterTargetMachine X(getTheLoongArch32Target()); RegisterTargetMachine Y(getTheLoongArch64Target()); + auto *PR = PassRegistry::getPassRegistry(); + initializeLoongArchPreRAExpandPseudoPass(*PR); } static std::string computeDataLayout(const Triple &TT) { @@ -103,6 +105,7 @@ void addIRPasses() override; bool addInstSelector() override; void addPreEmitPass2() override; + void addPreRegAlloc() override; }; } // end namespace @@ -129,3 +132,7 @@ // forward progress in the LL/SC block. addPass(createLoongArchExpandAtomicPseudoPass()); } + +void LoongArchPassConfig::addPreRegAlloc() { + addPass(createLoongArchPreRAExpandPseudoPass()); +} diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchBaseInfo.h b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchBaseInfo.h --- a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchBaseInfo.h +++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchBaseInfo.h @@ -31,6 +31,8 @@ MO_CALL_PLT, MO_PCREL_HI, MO_PCREL_LO, + MO_GOT_PC_HI, + MO_GOT_PC_LO, // TODO: Add more flags. }; } // end namespace LoongArchII diff --git a/llvm/test/CodeGen/LoongArch/block-address.ll b/llvm/test/CodeGen/LoongArch/block-address.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/LoongArch/block-address.ll @@ -0,0 +1,39 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc --mtriple=loongarch32 < %s | FileCheck %s --check-prefix=LA32 +; RUN: llc --mtriple=loongarch64 < %s | FileCheck %s --check-prefix=LA64 + +@addr = dso_local global ptr null + +define void @test_blockaddress() nounwind { +; LA32-LABEL: test_blockaddress: +; LA32: # %bb.0: +; LA32-NEXT: pcalau12i $a0, %pc_hi20(addr) +; LA32-NEXT: addi.w $a0, $a0, %pc_lo12(addr) +; LA32-NEXT: pcalau12i $a1, %pc_hi20(.Ltmp0) +; LA32-NEXT: addi.w $a1, $a1, %pc_lo12(.Ltmp0) +; LA32-NEXT: st.w $a1, $a0, 0 +; LA32-NEXT: ld.w $a0, $a0, 0 +; LA32-NEXT: jr $a0 +; LA32-NEXT: .Ltmp0: # Block address taken +; LA32-NEXT: .LBB0_1: # %block +; LA32-NEXT: ret +; +; LA64-LABEL: test_blockaddress: +; LA64: # %bb.0: +; LA64-NEXT: pcalau12i $a0, %pc_hi20(addr) +; LA64-NEXT: addi.d $a0, $a0, %pc_lo12(addr) +; LA64-NEXT: pcalau12i $a1, %pc_hi20(.Ltmp0) +; LA64-NEXT: addi.d $a1, $a1, %pc_lo12(.Ltmp0) +; LA64-NEXT: st.d $a1, $a0, 0 +; LA64-NEXT: ld.d $a0, $a0, 0 +; LA64-NEXT: jr $a0 +; LA64-NEXT: .Ltmp0: # Block address taken +; LA64-NEXT: .LBB0_1: # %block +; LA64-NEXT: ret + store volatile ptr blockaddress(@test_blockaddress, %block), ptr @addr + %val = load volatile ptr, ptr @addr + indirectbr ptr %val, [label %block] + +block: + ret void +} diff --git a/llvm/test/CodeGen/LoongArch/calling-conv-lp64d.ll b/llvm/test/CodeGen/LoongArch/calling-conv-lp64d.ll --- a/llvm/test/CodeGen/LoongArch/calling-conv-lp64d.ll +++ b/llvm/test/CodeGen/LoongArch/calling-conv-lp64d.ll @@ -462,30 +462,30 @@ ; CHECK: # %bb.0: ; CHECK-NEXT: addi.d $sp, $sp, -16 ; CHECK-NEXT: st.d $ra, $sp, 8 # 8-byte Folded Spill -; CHECK-NEXT: pcalau12i $a0, .LCPI21_0 -; CHECK-NEXT: addi.d $a0, $a0, .LCPI21_0 -; CHECK-NEXT: pcalau12i $a1, .LCPI21_1 -; CHECK-NEXT: addi.d $a1, $a1, .LCPI21_1 -; CHECK-NEXT: pcalau12i $a2, .LCPI21_2 -; CHECK-NEXT: addi.d $a2, $a2, .LCPI21_2 -; CHECK-NEXT: pcalau12i $a3, .LCPI21_3 -; CHECK-NEXT: addi.d $a3, $a3, .LCPI21_3 -; CHECK-NEXT: pcalau12i $a4, .LCPI21_4 -; CHECK-NEXT: addi.d $a4, $a4, .LCPI21_4 -; CHECK-NEXT: pcalau12i $a5, .LCPI21_5 -; CHECK-NEXT: addi.d $a5, $a5, .LCPI21_5 -; CHECK-NEXT: addi.d $a6, $zero, 1 -; CHECK-NEXT: movgr2fr.d $fa0, $a6 -; CHECK-NEXT: ffint.d.l $fa0, $fa0 -; CHECK-NEXT: fld.d $fa1, $a5, 0 -; CHECK-NEXT: fld.d $fa2, $a4, 0 -; CHECK-NEXT: fld.d $fa3, $a3, 0 -; CHECK-NEXT: fld.d $fa4, $a2, 0 -; CHECK-NEXT: fld.d $fa5, $a1, 0 +; CHECK-NEXT: pcalau12i $a0, %pc_hi20(.LCPI21_0) +; CHECK-NEXT: addi.d $a0, $a0, %pc_lo12(.LCPI21_0) +; CHECK-NEXT: fld.d $fa1, $a0, 0 +; CHECK-NEXT: pcalau12i $a0, %pc_hi20(.LCPI21_1) +; CHECK-NEXT: addi.d $a0, $a0, %pc_lo12(.LCPI21_1) +; CHECK-NEXT: fld.d $fa2, $a0, 0 +; CHECK-NEXT: pcalau12i $a0, %pc_hi20(.LCPI21_2) +; CHECK-NEXT: addi.d $a0, $a0, %pc_lo12(.LCPI21_2) +; CHECK-NEXT: fld.d $fa3, $a0, 0 +; CHECK-NEXT: pcalau12i $a0, %pc_hi20(.LCPI21_3) +; CHECK-NEXT: addi.d $a0, $a0, %pc_lo12(.LCPI21_3) +; CHECK-NEXT: fld.d $fa4, $a0, 0 +; CHECK-NEXT: pcalau12i $a0, %pc_hi20(.LCPI21_4) +; CHECK-NEXT: addi.d $a0, $a0, %pc_lo12(.LCPI21_4) +; CHECK-NEXT: fld.d $fa5, $a0, 0 +; CHECK-NEXT: pcalau12i $a0, %pc_hi20(.LCPI21_5) +; CHECK-NEXT: addi.d $a0, $a0, %pc_lo12(.LCPI21_5) ; CHECK-NEXT: fld.d $fa6, $a0, 0 -; CHECK-NEXT: pcalau12i $a0, .LCPI21_6 -; CHECK-NEXT: addi.d $a0, $a0, .LCPI21_6 +; CHECK-NEXT: pcalau12i $a0, %pc_hi20(.LCPI21_6) +; CHECK-NEXT: addi.d $a0, $a0, %pc_lo12(.LCPI21_6) ; CHECK-NEXT: fld.d $fa7, $a0, 0 +; CHECK-NEXT: addi.d $a0, $zero, 1 +; CHECK-NEXT: movgr2fr.d $fa0, $a0 +; CHECK-NEXT: ffint.d.l $fa0, $fa0 ; CHECK-NEXT: ori $a0, $zero, 0 ; CHECK-NEXT: lu32i.d $a0, 131072 ; CHECK-NEXT: lu52i.d $a0, $a0, 1026 diff --git a/llvm/test/CodeGen/LoongArch/double-imm.ll b/llvm/test/CodeGen/LoongArch/double-imm.ll --- a/llvm/test/CodeGen/LoongArch/double-imm.ll +++ b/llvm/test/CodeGen/LoongArch/double-imm.ll @@ -35,15 +35,15 @@ define double @f64_constant_pi() nounwind { ; LA32-LABEL: f64_constant_pi: ; LA32: # %bb.0: -; LA32-NEXT: pcalau12i $a0, .LCPI2_0 -; LA32-NEXT: addi.w $a0, $a0, .LCPI2_0 +; LA32-NEXT: pcalau12i $a0, %pc_hi20(.LCPI2_0) +; LA32-NEXT: addi.w $a0, $a0, %pc_lo12(.LCPI2_0) ; LA32-NEXT: fld.d $fa0, $a0, 0 ; LA32-NEXT: ret ; ; LA64-LABEL: f64_constant_pi: ; LA64: # %bb.0: -; LA64-NEXT: pcalau12i $a0, .LCPI2_0 -; LA64-NEXT: addi.d $a0, $a0, .LCPI2_0 +; LA64-NEXT: pcalau12i $a0, %pc_hi20(.LCPI2_0) +; LA64-NEXT: addi.d $a0, $a0, %pc_lo12(.LCPI2_0) ; LA64-NEXT: fld.d $fa0, $a0, 0 ; LA64-NEXT: ret ret double 3.1415926535897931159979634685441851615905761718750 diff --git a/llvm/test/CodeGen/LoongArch/float-imm.ll b/llvm/test/CodeGen/LoongArch/float-imm.ll --- a/llvm/test/CodeGen/LoongArch/float-imm.ll +++ b/llvm/test/CodeGen/LoongArch/float-imm.ll @@ -33,15 +33,15 @@ define float @f32_constant_pi() nounwind { ; LA32-LABEL: f32_constant_pi: ; LA32: # %bb.0: -; LA32-NEXT: pcalau12i $a0, .LCPI2_0 -; LA32-NEXT: addi.w $a0, $a0, .LCPI2_0 +; LA32-NEXT: pcalau12i $a0, %pc_hi20(.LCPI2_0) +; LA32-NEXT: addi.w $a0, $a0, %pc_lo12(.LCPI2_0) ; LA32-NEXT: fld.s $fa0, $a0, 0 ; LA32-NEXT: ret ; ; LA64-LABEL: f32_constant_pi: ; LA64: # %bb.0: -; LA64-NEXT: pcalau12i $a0, .LCPI2_0 -; LA64-NEXT: addi.d $a0, $a0, .LCPI2_0 +; LA64-NEXT: pcalau12i $a0, %pc_hi20(.LCPI2_0) +; LA64-NEXT: addi.d $a0, $a0, %pc_lo12(.LCPI2_0) ; LA64-NEXT: fld.s $fa0, $a0, 0 ; LA64-NEXT: ret ret float 3.14159274101257324218750 diff --git a/llvm/test/CodeGen/LoongArch/global-address.ll b/llvm/test/CodeGen/LoongArch/global-address.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/LoongArch/global-address.ll @@ -0,0 +1,53 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc --mtriple=loongarch32 --relocation-model=static < %s | FileCheck %s --check-prefix=LA32NOPIC +; RUN: llc --mtriple=loongarch32 --relocation-model=pic < %s | FileCheck %s --check-prefix=LA32PIC +; RUN: llc --mtriple=loongarch64 --relocation-model=static < %s | FileCheck %s --check-prefix=LA64NOPIC +; RUN: llc --mtriple=loongarch64 --relocation-model=pic < %s | FileCheck %s --check-prefix=LA64PIC + +@g = dso_local global i32 zeroinitializer, align 4 +@G = global i32 zeroinitializer, align 4 + +define void @foo() nounwind { +; LA32NOPIC-LABEL: foo: +; LA32NOPIC: # %bb.0: +; LA32NOPIC-NEXT: pcalau12i $a0, %got_hi20(G) +; LA32NOPIC-NEXT: ld.w $a0, $a0, %got_lo12(G) +; LA32NOPIC-NEXT: ld.w $a0, $a0, 0 +; LA32NOPIC-NEXT: pcalau12i $a0, %pc_hi20(g) +; LA32NOPIC-NEXT: addi.w $a0, $a0, %pc_lo12(g) +; LA32NOPIC-NEXT: ld.w $a0, $a0, 0 +; LA32NOPIC-NEXT: ret +; +; LA32PIC-LABEL: foo: +; LA32PIC: # %bb.0: +; LA32PIC-NEXT: pcalau12i $a0, %got_hi20(G) +; LA32PIC-NEXT: ld.w $a0, $a0, %got_lo12(G) +; LA32PIC-NEXT: ld.w $a0, $a0, 0 +; LA32PIC-NEXT: pcalau12i $a0, %pc_hi20(.Lg$local) +; LA32PIC-NEXT: addi.w $a0, $a0, %pc_lo12(.Lg$local) +; LA32PIC-NEXT: ld.w $a0, $a0, 0 +; LA32PIC-NEXT: ret +; +; LA64NOPIC-LABEL: foo: +; LA64NOPIC: # %bb.0: +; LA64NOPIC-NEXT: pcalau12i $a0, %got_hi20(G) +; LA64NOPIC-NEXT: ld.d $a0, $a0, %got_lo12(G) +; LA64NOPIC-NEXT: ld.w $a0, $a0, 0 +; LA64NOPIC-NEXT: pcalau12i $a0, %pc_hi20(g) +; LA64NOPIC-NEXT: addi.d $a0, $a0, %pc_lo12(g) +; LA64NOPIC-NEXT: ld.w $a0, $a0, 0 +; LA64NOPIC-NEXT: ret +; +; LA64PIC-LABEL: foo: +; LA64PIC: # %bb.0: +; LA64PIC-NEXT: pcalau12i $a0, %got_hi20(G) +; LA64PIC-NEXT: ld.d $a0, $a0, %got_lo12(G) +; LA64PIC-NEXT: ld.w $a0, $a0, 0 +; LA64PIC-NEXT: pcalau12i $a0, %pc_hi20(.Lg$local) +; LA64PIC-NEXT: addi.d $a0, $a0, %pc_lo12(.Lg$local) +; LA64PIC-NEXT: ld.w $a0, $a0, 0 +; LA64PIC-NEXT: ret + %V = load volatile i32, ptr @G + %v = load volatile i32, ptr @g + ret void +} diff --git a/llvm/test/CodeGen/LoongArch/ir-instruction/double-convert.ll b/llvm/test/CodeGen/LoongArch/ir-instruction/double-convert.ll --- a/llvm/test/CodeGen/LoongArch/ir-instruction/double-convert.ll +++ b/llvm/test/CodeGen/LoongArch/ir-instruction/double-convert.ll @@ -116,8 +116,8 @@ define i32 @convert_double_to_u32(double %a) nounwind { ; LA32-LABEL: convert_double_to_u32: ; LA32: # %bb.0: -; LA32-NEXT: pcalau12i $a0, .LCPI7_0 -; LA32-NEXT: addi.w $a0, $a0, .LCPI7_0 +; LA32-NEXT: pcalau12i $a0, %pc_hi20(.LCPI7_0) +; LA32-NEXT: addi.w $a0, $a0, %pc_lo12(.LCPI7_0) ; LA32-NEXT: fld.d $fa1, $a0, 0 ; LA32-NEXT: fsub.d $fa2, $fa0, $fa1 ; LA32-NEXT: ftintrz.w.d $fa2, $fa2 @@ -173,8 +173,8 @@ ; ; LA64-LABEL: convert_double_to_u64: ; LA64: # %bb.0: -; LA64-NEXT: pcalau12i $a0, .LCPI9_0 -; LA64-NEXT: addi.d $a0, $a0, .LCPI9_0 +; LA64-NEXT: pcalau12i $a0, %pc_hi20(.LCPI9_0) +; LA64-NEXT: addi.d $a0, $a0, %pc_lo12(.LCPI9_0) ; LA64-NEXT: fld.d $fa1, $a0, 0 ; LA64-NEXT: fsub.d $fa2, $fa0, $fa1 ; LA64-NEXT: ftintrz.l.d $fa2, $fa2 @@ -232,8 +232,8 @@ ; LA32-NEXT: lu12i.w $a1, 275200 ; LA32-NEXT: st.w $a1, $sp, 12 ; LA32-NEXT: st.w $a0, $sp, 8 -; LA32-NEXT: pcalau12i $a0, .LCPI12_0 -; LA32-NEXT: addi.w $a0, $a0, .LCPI12_0 +; LA32-NEXT: pcalau12i $a0, %pc_hi20(.LCPI12_0) +; LA32-NEXT: addi.w $a0, $a0, %pc_lo12(.LCPI12_0) ; LA32-NEXT: fld.d $fa0, $a0, 0 ; LA32-NEXT: fld.d $fa1, $sp, 8 ; LA32-NEXT: fsub.d $fa0, $fa1, $fa0 @@ -242,12 +242,12 @@ ; ; LA64-LABEL: convert_u32_to_double: ; LA64: # %bb.0: +; LA64-NEXT: pcalau12i $a1, %pc_hi20(.LCPI12_0) +; LA64-NEXT: addi.d $a1, $a1, %pc_lo12(.LCPI12_0) +; LA64-NEXT: fld.d $fa0, $a1, 0 ; LA64-NEXT: lu52i.d $a1, $zero, 1107 -; LA64-NEXT: movgr2fr.d $fa0, $a1 -; LA64-NEXT: pcalau12i $a1, .LCPI12_0 -; LA64-NEXT: addi.d $a1, $a1, .LCPI12_0 -; LA64-NEXT: fld.d $fa1, $a1, 0 -; LA64-NEXT: fsub.d $fa0, $fa0, $fa1 +; LA64-NEXT: movgr2fr.d $fa1, $a1 +; LA64-NEXT: fsub.d $fa0, $fa1, $fa0 ; LA64-NEXT: lu12i.w $a1, 275200 ; LA64-NEXT: bstrins.d $a0, $a1, 63, 32 ; LA64-NEXT: movgr2fr.d $fa1, $a0 @@ -273,8 +273,8 @@ ; LA64-NEXT: lu52i.d $a2, $zero, 1107 ; LA64-NEXT: or $a1, $a1, $a2 ; LA64-NEXT: movgr2fr.d $fa0, $a1 -; LA64-NEXT: pcalau12i $a1, .LCPI13_0 -; LA64-NEXT: addi.d $a1, $a1, .LCPI13_0 +; LA64-NEXT: pcalau12i $a1, %pc_hi20(.LCPI13_0) +; LA64-NEXT: addi.d $a1, $a1, %pc_lo12(.LCPI13_0) ; LA64-NEXT: fld.d $fa1, $a1, 0 ; LA64-NEXT: fsub.d $fa0, $fa0, $fa1 ; LA64-NEXT: lu12i.w $a1, 275200 diff --git a/llvm/test/CodeGen/LoongArch/ir-instruction/float-convert.ll b/llvm/test/CodeGen/LoongArch/ir-instruction/float-convert.ll --- a/llvm/test/CodeGen/LoongArch/ir-instruction/float-convert.ll +++ b/llvm/test/CodeGen/LoongArch/ir-instruction/float-convert.ll @@ -181,8 +181,8 @@ define i32 @convert_float_to_u32(float %a) nounwind { ; LA32F-LABEL: convert_float_to_u32: ; LA32F: # %bb.0: -; LA32F-NEXT: pcalau12i $a0, .LCPI6_0 -; LA32F-NEXT: addi.w $a0, $a0, .LCPI6_0 +; LA32F-NEXT: pcalau12i $a0, %pc_hi20(.LCPI6_0) +; LA32F-NEXT: addi.w $a0, $a0, %pc_lo12(.LCPI6_0) ; LA32F-NEXT: fld.s $fa1, $a0, 0 ; LA32F-NEXT: fsub.s $fa2, $fa0, $fa1 ; LA32F-NEXT: ftintrz.w.s $fa2, $fa2 @@ -200,8 +200,8 @@ ; ; LA32D-LABEL: convert_float_to_u32: ; LA32D: # %bb.0: -; LA32D-NEXT: pcalau12i $a0, .LCPI6_0 -; LA32D-NEXT: addi.w $a0, $a0, .LCPI6_0 +; LA32D-NEXT: pcalau12i $a0, %pc_hi20(.LCPI6_0) +; LA32D-NEXT: addi.w $a0, $a0, %pc_lo12(.LCPI6_0) ; LA32D-NEXT: fld.s $fa1, $a0, 0 ; LA32D-NEXT: fsub.s $fa2, $fa0, $fa1 ; LA32D-NEXT: ftintrz.w.s $fa2, $fa2 @@ -219,8 +219,8 @@ ; ; LA64F-LABEL: convert_float_to_u32: ; LA64F: # %bb.0: -; LA64F-NEXT: pcalau12i $a0, .LCPI6_0 -; LA64F-NEXT: addi.d $a0, $a0, .LCPI6_0 +; LA64F-NEXT: pcalau12i $a0, %pc_hi20(.LCPI6_0) +; LA64F-NEXT: addi.d $a0, $a0, %pc_lo12(.LCPI6_0) ; LA64F-NEXT: fld.s $fa1, $a0, 0 ; LA64F-NEXT: fsub.s $fa2, $fa0, $fa1 ; LA64F-NEXT: ftintrz.w.s $fa2, $fa2 @@ -266,8 +266,8 @@ ; ; LA64F-LABEL: convert_float_to_u64: ; LA64F: # %bb.0: -; LA64F-NEXT: pcalau12i $a0, .LCPI7_0 -; LA64F-NEXT: addi.d $a0, $a0, .LCPI7_0 +; LA64F-NEXT: pcalau12i $a0, %pc_hi20(.LCPI7_0) +; LA64F-NEXT: addi.d $a0, $a0, %pc_lo12(.LCPI7_0) ; LA64F-NEXT: fld.s $fa1, $a0, 0 ; LA64F-NEXT: fsub.s $fa2, $fa0, $fa1 ; LA64F-NEXT: ftintrz.w.s $fa2, $fa2 @@ -285,8 +285,8 @@ ; ; LA64D-LABEL: convert_float_to_u64: ; LA64D: # %bb.0: -; LA64D-NEXT: pcalau12i $a0, .LCPI7_0 -; LA64D-NEXT: addi.d $a0, $a0, .LCPI7_0 +; LA64D-NEXT: pcalau12i $a0, %pc_hi20(.LCPI7_0) +; LA64D-NEXT: addi.d $a0, $a0, %pc_lo12(.LCPI7_0) ; LA64D-NEXT: fld.s $fa1, $a0, 0 ; LA64D-NEXT: fsub.s $fa2, $fa0, $fa1 ; LA64D-NEXT: ftintrz.l.s $fa2, $fa2 @@ -503,8 +503,8 @@ ; LA32D-NEXT: lu12i.w $a1, 275200 ; LA32D-NEXT: st.w $a1, $sp, 12 ; LA32D-NEXT: st.w $a0, $sp, 8 -; LA32D-NEXT: pcalau12i $a0, .LCPI14_0 -; LA32D-NEXT: addi.w $a0, $a0, .LCPI14_0 +; LA32D-NEXT: pcalau12i $a0, %pc_hi20(.LCPI14_0) +; LA32D-NEXT: addi.w $a0, $a0, %pc_lo12(.LCPI14_0) ; LA32D-NEXT: fld.d $fa0, $a0, 0 ; LA32D-NEXT: fld.d $fa1, $sp, 8 ; LA32D-NEXT: fsub.d $fa0, $fa1, $fa0 diff --git a/llvm/test/CodeGen/LoongArch/jump-table.ll b/llvm/test/CodeGen/LoongArch/jump-table.ll --- a/llvm/test/CodeGen/LoongArch/jump-table.ll +++ b/llvm/test/CodeGen/LoongArch/jump-table.ll @@ -1,8 +1,17 @@ ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py -; RUN: llc --mtriple=loongarch32 --verify-machineinstrs < %s \ +; RUN: llc --mtriple=loongarch32 --min-jump-table-entries=5 < %s \ ; RUN: | FileCheck %s --check-prefix=LA32 -; RUN: llc --mtriple=loongarch64 --verify-machineinstrs < %s \ +; RUN: llc --mtriple=loongarch64 --min-jump-table-entries=5 < %s \ ; RUN: | FileCheck %s --check-prefix=LA64 +; RUN: llc --mtriple=loongarch32 --min-jump-table-entries=4 < %s \ +; RUN: | FileCheck %s --check-prefix=LA32-JT +; RUN: llc --mtriple=loongarch64 --min-jump-table-entries=4 < %s \ +; RUN: | FileCheck %s --check-prefix=LA64-JT + +;; The default mininum number of entries to use a jump table is 4. +;; +;; Note: The parameter `--min-jump-table-entries` will have no effect once we +;; have set the default value using `setMinimumJumpTableEntries`. define void @switch_4_arms(i32 %in, ptr %out) nounwind { ; LA32-LABEL: switch_4_arms: @@ -69,6 +78,55 @@ ; LA64-NEXT: st.w $a2, $a1, 0 ; LA64-NEXT: .LBB0_10: # %exit ; LA64-NEXT: ret +; +; LA32-JT-LABEL: switch_4_arms: +; LA32-JT: # %bb.0: # %entry +; LA32-JT-NEXT: addi.w $a2, $a0, -1 +; LA32-JT-NEXT: ori $a0, $zero, 3 +; LA32-JT-NEXT: bltu $a0, $a2, .LBB0_6 +; LA32-JT-NEXT: # %bb.1: # %entry +; LA32-JT-NEXT: pcalau12i $a3, %pc_hi20(.LJTI0_0) +; LA32-JT-NEXT: addi.w $a3, $a3, %pc_lo12(.LJTI0_0) +; LA32-JT-NEXT: alsl.w $a2, $a2, $a3, 2 +; LA32-JT-NEXT: ld.w $a2, $a2, 0 +; LA32-JT-NEXT: jr $a2 +; LA32-JT-NEXT: .LBB0_2: # %bb1 +; LA32-JT-NEXT: ori $a0, $zero, 4 +; LA32-JT-NEXT: b .LBB0_5 +; LA32-JT-NEXT: .LBB0_3: # %bb3 +; LA32-JT-NEXT: ori $a0, $zero, 2 +; LA32-JT-NEXT: b .LBB0_5 +; LA32-JT-NEXT: .LBB0_4: # %bb4 +; LA32-JT-NEXT: ori $a0, $zero, 1 +; LA32-JT-NEXT: .LBB0_5: # %exit +; LA32-JT-NEXT: st.w $a0, $a1, 0 +; LA32-JT-NEXT: .LBB0_6: # %exit +; LA32-JT-NEXT: ret +; +; LA64-JT-LABEL: switch_4_arms: +; LA64-JT: # %bb.0: # %entry +; LA64-JT-NEXT: bstrpick.d $a0, $a0, 31, 0 +; LA64-JT-NEXT: addi.d $a2, $a0, -1 +; LA64-JT-NEXT: ori $a0, $zero, 3 +; LA64-JT-NEXT: bltu $a0, $a2, .LBB0_6 +; LA64-JT-NEXT: # %bb.1: # %entry +; LA64-JT-NEXT: slli.d $a2, $a2, 3 +; LA64-JT-NEXT: pcalau12i $a3, %pc_hi20(.LJTI0_0) +; LA64-JT-NEXT: addi.d $a3, $a3, %pc_lo12(.LJTI0_0) +; LA64-JT-NEXT: ldx.d $a2, $a2, $a3 +; LA64-JT-NEXT: jr $a2 +; LA64-JT-NEXT: .LBB0_2: # %bb1 +; LA64-JT-NEXT: ori $a0, $zero, 4 +; LA64-JT-NEXT: b .LBB0_5 +; LA64-JT-NEXT: .LBB0_3: # %bb3 +; LA64-JT-NEXT: ori $a0, $zero, 2 +; LA64-JT-NEXT: b .LBB0_5 +; LA64-JT-NEXT: .LBB0_4: # %bb4 +; LA64-JT-NEXT: ori $a0, $zero, 1 +; LA64-JT-NEXT: .LBB0_5: # %exit +; LA64-JT-NEXT: st.w $a0, $a1, 0 +; LA64-JT-NEXT: .LBB0_6: # %exit +; LA64-JT-NEXT: ret entry: switch i32 %in, label %exit [ i32 1, label %bb1