diff --git a/llvm/lib/Target/LoongArch/LoongArchExpandPseudoInsts.cpp b/llvm/lib/Target/LoongArch/LoongArchExpandPseudoInsts.cpp index 0218934ea3344..c2d73a260b1c1 100644 --- a/llvm/lib/Target/LoongArch/LoongArchExpandPseudoInsts.cpp +++ b/llvm/lib/Target/LoongArch/LoongArchExpandPseudoInsts.cpp @@ -187,18 +187,21 @@ bool LoongArchPreRAExpandPseudo::expandPcalau12iInstPair( MachineInstr &MI = *MBBI; DebugLoc DL = MI.getDebugLoc(); + const auto &STI = MF->getSubtarget(); + bool EnableRelax = STI.hasFeature(LoongArch::FeatureRelax); + 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); + .addDisp(Symbol, 0, LoongArchII::encodeFlags(FlagsHi, EnableRelax)); MachineInstr *SecondMI = BuildMI(MBB, MBBI, DL, TII->get(SecondOpcode), DestReg) .addReg(ScratchReg) - .addDisp(Symbol, 0, FlagsLo); + .addDisp(Symbol, 0, LoongArchII::encodeFlags(FlagsLo, EnableRelax)); if (MI.hasOneMemOperand()) SecondMI->addMemOperand(*MF, *MI.memoperands_begin()); @@ -481,6 +484,7 @@ bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSDesc( unsigned ADD = STI.is64Bit() ? LoongArch::ADD_D : LoongArch::ADD_W; unsigned ADDI = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W; unsigned LD = STI.is64Bit() ? LoongArch::LD_D : LoongArch::LD_W; + bool EnableRelax = STI.hasFeature(LoongArch::FeatureRelax); Register DestReg = MI.getOperand(0).getReg(); Register Tmp1Reg = @@ -488,7 +492,9 @@ bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSDesc( MachineOperand &Symbol = MI.getOperand(Large ? 2 : 1); BuildMI(MBB, MBBI, DL, TII->get(LoongArch::PCALAU12I), Tmp1Reg) - .addDisp(Symbol, 0, LoongArchII::MO_DESC_PC_HI); + .addDisp(Symbol, 0, + LoongArchII::encodeFlags(LoongArchII::MO_DESC_PC_HI, + EnableRelax && !Large)); if (Large) { // Code Sequence: @@ -526,19 +532,25 @@ bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSDesc( // pcalau12i $a0, %desc_pc_hi20(sym) // addi.w/d $a0, $a0, %desc_pc_lo12(sym) // ld.w/d $ra, $a0, %desc_ld(sym) - // jirl $ra, $ra, %desc_ld(sym) - // add.d $dst, $a0, $tp + // jirl $ra, $ra, %desc_call(sym) + // add.w/d $dst, $a0, $tp BuildMI(MBB, MBBI, DL, TII->get(ADDI), LoongArch::R4) .addReg(Tmp1Reg) - .addDisp(Symbol, 0, LoongArchII::MO_DESC_PC_LO); + .addDisp( + Symbol, 0, + LoongArchII::encodeFlags(LoongArchII::MO_DESC_PC_LO, EnableRelax)); } BuildMI(MBB, MBBI, DL, TII->get(LD), LoongArch::R1) .addReg(LoongArch::R4) - .addDisp(Symbol, 0, LoongArchII::MO_DESC_LD); + .addDisp(Symbol, 0, + LoongArchII::encodeFlags(LoongArchII::MO_DESC_LD, + EnableRelax && !Large)); BuildMI(MBB, MBBI, DL, TII->get(LoongArch::PseudoDESC_CALL), LoongArch::R1) .addReg(LoongArch::R1) - .addDisp(Symbol, 0, LoongArchII::MO_DESC_CALL); + .addDisp(Symbol, 0, + LoongArchII::encodeFlags(LoongArchII::MO_DESC_CALL, + EnableRelax && !Large)); BuildMI(MBB, MBBI, DL, TII->get(ADD), DestReg) .addReg(LoongArch::R4) .addReg(LoongArch::R2); diff --git a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.cpp b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.cpp index 32bc8bb801295..4e49ba6e339a6 100644 --- a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.cpp +++ b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.cpp @@ -455,6 +455,83 @@ bool LoongArchInstrInfo::isSchedulingBoundary(const MachineInstr &MI, break; } + const auto &STI = MF.getSubtarget(); + if (STI.hasFeature(LoongArch::FeatureRelax)) { + // When linker relaxation enabled, the following instruction patterns are + // prohibited from being reordered: + // + // * pcalau12i $a0, %pc_hi20(s) + // addi.w/d $a0, $a0, %pc_lo12(s) + // + // * pcalau12i $a0, %got_pc_hi20(s) + // ld.w/d $a0, $a0, %got_pc_lo12(s) + // + // * pcalau12i $a0, %ld_pc_hi20(s) | %gd_pc_hi20(s) + // addi.w/d $a0, $a0, %got_pc_lo12(s) + // + // * pcalau12i $a0, %desc_pc_hi20(s) + // addi.w/d $a0, $a0, %desc_pc_lo12(s) + // ld.w/d $ra, $a0, %desc_ld(s) + // jirl $ra, $ra, %desc_call(s) + unsigned AddiOp = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W; + unsigned LdOp = STI.is64Bit() ? LoongArch::LD_D : LoongArch::LD_W; + switch (MI.getOpcode()) { + case LoongArch::PCALAU12I: { + auto MO0 = LoongArchII::getDirectFlags(MI.getOperand(1)); + auto SecondOp = std::next(MII); + if (MO0 == LoongArchII::MO_DESC_PC_HI) { + if (SecondOp == MIE || SecondOp->getOpcode() != AddiOp) + break; + auto Ld = std::next(SecondOp); + if (Ld == MIE || Ld->getOpcode() != LdOp) + break; + auto MO1 = LoongArchII::getDirectFlags(SecondOp->getOperand(2)); + auto MO2 = LoongArchII::getDirectFlags(Ld->getOperand(2)); + if (MO1 == LoongArchII::MO_DESC_PC_LO && MO2 == LoongArchII::MO_DESC_LD) + return true; + break; + } + if (SecondOp == MIE || + (SecondOp->getOpcode() != AddiOp && SecondOp->getOpcode() != LdOp)) + break; + auto MO1 = LoongArchII::getDirectFlags(SecondOp->getOperand(2)); + if (MO0 == LoongArchII::MO_PCREL_HI && SecondOp->getOpcode() == AddiOp && + MO1 == LoongArchII::MO_PCREL_LO) + return true; + if (MO0 == LoongArchII::MO_GOT_PC_HI && SecondOp->getOpcode() == LdOp && + MO1 == LoongArchII::MO_GOT_PC_LO) + return true; + if ((MO0 == LoongArchII::MO_LD_PC_HI || + MO0 == LoongArchII::MO_GD_PC_HI) && + SecondOp->getOpcode() == AddiOp && MO1 == LoongArchII::MO_GOT_PC_LO) + return true; + break; + } + case LoongArch::ADDI_W: + case LoongArch::ADDI_D: { + auto MO = LoongArchII::getDirectFlags(MI.getOperand(2)); + if (MO == LoongArchII::MO_PCREL_LO || MO == LoongArchII::MO_GOT_PC_LO) + return true; + break; + } + case LoongArch::LD_W: + case LoongArch::LD_D: { + auto MO = LoongArchII::getDirectFlags(MI.getOperand(2)); + if (MO == LoongArchII::MO_GOT_PC_LO) + return true; + break; + } + case LoongArch::PseudoDESC_CALL: { + auto MO = LoongArchII::getDirectFlags(MI.getOperand(2)); + if (MO == LoongArchII::MO_DESC_CALL) + return true; + break; + } + default: + break; + } + } + return false; } @@ -630,7 +707,8 @@ bool LoongArchInstrInfo::reverseBranchCondition( std::pair LoongArchInstrInfo::decomposeMachineOperandsTargetFlags(unsigned TF) const { - return std::make_pair(TF, 0u); + const unsigned Mask = LoongArchII::MO_DIRECT_FLAG_MASK; + return std::make_pair(TF & Mask, TF & ~Mask); } ArrayRef> @@ -656,20 +734,29 @@ LoongArchInstrInfo::getSerializableDirectMachineOperandTargetFlags() const { {MO_IE_PC_LO, "loongarch-ie-pc-lo"}, {MO_IE_PC64_LO, "loongarch-ie-pc64-lo"}, {MO_IE_PC64_HI, "loongarch-ie-pc64-hi"}, + {MO_LD_PC_HI, "loongarch-ld-pc-hi"}, + {MO_GD_PC_HI, "loongarch-gd-pc-hi"}, + {MO_CALL36, "loongarch-call36"}, {MO_DESC_PC_HI, "loongarch-desc-pc-hi"}, {MO_DESC_PC_LO, "loongarch-desc-pc-lo"}, {MO_DESC64_PC_LO, "loongarch-desc64-pc-lo"}, {MO_DESC64_PC_HI, "loongarch-desc64-pc-hi"}, {MO_DESC_LD, "loongarch-desc-ld"}, {MO_DESC_CALL, "loongarch-desc-call"}, - {MO_LD_PC_HI, "loongarch-ld-pc-hi"}, - {MO_GD_PC_HI, "loongarch-gd-pc-hi"}, {MO_LE_HI_R, "loongarch-le-hi-r"}, {MO_LE_ADD_R, "loongarch-le-add-r"}, {MO_LE_LO_R, "loongarch-le-lo-r"}}; return ArrayRef(TargetFlags); } +ArrayRef> +LoongArchInstrInfo::getSerializableBitmaskMachineOperandTargetFlags() const { + using namespace LoongArchII; + static const std::pair TargetFlags[] = { + {MO_RELAX, "loongarch-relax"}}; + return ArrayRef(TargetFlags); +} + // Returns true if this is the sext.w pattern, addi.w rd, rs, 0. bool LoongArch::isSEXT_W(const MachineInstr &MI) { return MI.getOpcode() == LoongArch::ADDI_W && MI.getOperand(1).isReg() && diff --git a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.h b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.h index ef9970783107e..a5b31878bfa1c 100644 --- a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.h +++ b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.h @@ -91,6 +91,9 @@ class LoongArchInstrInfo : public LoongArchGenInstrInfo { ArrayRef> getSerializableDirectMachineOperandTargetFlags() const override; + ArrayRef> + getSerializableBitmaskMachineOperandTargetFlags() const override; + protected: const LoongArchSubtarget &STI; }; diff --git a/llvm/lib/Target/LoongArch/LoongArchMCInstLower.cpp b/llvm/lib/Target/LoongArch/LoongArchMCInstLower.cpp index d1de0609f24ce..d87ed068ebff8 100644 --- a/llvm/lib/Target/LoongArch/LoongArchMCInstLower.cpp +++ b/llvm/lib/Target/LoongArch/LoongArchMCInstLower.cpp @@ -27,7 +27,7 @@ static MCOperand lowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym, MCContext &Ctx = AP.OutContext; LoongArchMCExpr::VariantKind Kind; - switch (MO.getTargetFlags()) { + switch (LoongArchII::getDirectFlags(MO)) { default: llvm_unreachable("Unknown target flag on GV operand"); case LoongArchII::MO_None: @@ -134,7 +134,7 @@ static MCOperand lowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym, ME, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx); if (Kind != LoongArchMCExpr::VK_LoongArch_None) - ME = LoongArchMCExpr::create(ME, Kind, Ctx); + ME = LoongArchMCExpr::create(ME, Kind, Ctx, LoongArchII::hasRelaxFlag(MO)); return MCOperand::createExpr(ME); } diff --git a/llvm/lib/Target/LoongArch/LoongArchMergeBaseOffset.cpp b/llvm/lib/Target/LoongArch/LoongArchMergeBaseOffset.cpp index e9455fdd23ba5..7f98f7718a538 100644 --- a/llvm/lib/Target/LoongArch/LoongArchMergeBaseOffset.cpp +++ b/llvm/lib/Target/LoongArch/LoongArchMergeBaseOffset.cpp @@ -105,7 +105,7 @@ bool LoongArchMergeBaseOffsetOpt::detectFoldable(MachineInstr &Hi20, return false; const MachineOperand &Hi20Op1 = Hi20.getOperand(1); - if (Hi20Op1.getTargetFlags() != LoongArchII::MO_PCREL_HI) + if (LoongArchII::getDirectFlags(Hi20Op1) != LoongArchII::MO_PCREL_HI) return false; auto isGlobalOrCPIOrBlockAddress = [](const MachineOperand &Op) { @@ -157,7 +157,7 @@ bool LoongArchMergeBaseOffsetOpt::detectFoldable(MachineInstr &Hi20, const MachineOperand &Lo12Op2 = Lo12->getOperand(2); assert(Hi20.getOpcode() == LoongArch::PCALAU12I); - if (Lo12Op2.getTargetFlags() != LoongArchII::MO_PCREL_LO || + if (LoongArchII::getDirectFlags(Lo12Op2) != LoongArchII::MO_PCREL_LO || !(isGlobalOrCPIOrBlockAddress(Lo12Op2) || Lo12Op2.isMCSymbol()) || Lo12Op2.getOffset() != 0) return false; @@ -597,9 +597,28 @@ bool LoongArchMergeBaseOffsetOpt::foldIntoMemoryOps(MachineInstr &Hi20, if (!isInt<32>(NewOffset)) return false; + // If optimized by this pass successfully, MO_RELAX bitmask target-flag should + // be removed from the code sequence. + // + // For example: + // pcalau12i $a0, %pc_hi20(symbol) + // addi.d $a0, $a0, %pc_lo12(symbol) + // ld.w $a0, $a0, 0 + // + // => + // + // pcalau12i $a0, %pc_hi20(symbol) + // ld.w $a0, $a0, %pc_lo12(symbol) + // + // Code sequence optimized before can be relax by linker. But after being + // optimized, it cannot be relaxed any more. So MO_RELAX flag should not be + // carried by them. Hi20.getOperand(1).setOffset(NewOffset); + Hi20.getOperand(1).setTargetFlags( + LoongArchII::getDirectFlags(Hi20.getOperand(1))); MachineOperand &ImmOp = Lo12.getOperand(2); ImmOp.setOffset(NewOffset); + ImmOp.setTargetFlags(LoongArchII::getDirectFlags(ImmOp)); if (Lo20 && Hi12) { Lo20->getOperand(2).setOffset(NewOffset); Hi12->getOperand(2).setOffset(NewOffset); @@ -617,15 +636,16 @@ bool LoongArchMergeBaseOffsetOpt::foldIntoMemoryOps(MachineInstr &Hi20, switch (ImmOp.getType()) { case MachineOperand::MO_GlobalAddress: MO.ChangeToGA(ImmOp.getGlobal(), ImmOp.getOffset(), - ImmOp.getTargetFlags()); + LoongArchII::getDirectFlags(ImmOp)); break; case MachineOperand::MO_MCSymbol: - MO.ChangeToMCSymbol(ImmOp.getMCSymbol(), ImmOp.getTargetFlags()); + MO.ChangeToMCSymbol(ImmOp.getMCSymbol(), + LoongArchII::getDirectFlags(ImmOp)); MO.setOffset(ImmOp.getOffset()); break; case MachineOperand::MO_BlockAddress: MO.ChangeToBA(ImmOp.getBlockAddress(), ImmOp.getOffset(), - ImmOp.getTargetFlags()); + LoongArchII::getDirectFlags(ImmOp)); break; default: report_fatal_error("unsupported machine operand type"); diff --git a/llvm/lib/Target/LoongArch/LoongArchTargetMachine.cpp b/llvm/lib/Target/LoongArch/LoongArchTargetMachine.cpp index b611365f608af..62b08be5435cd 100644 --- a/llvm/lib/Target/LoongArch/LoongArchTargetMachine.cpp +++ b/llvm/lib/Target/LoongArch/LoongArchTargetMachine.cpp @@ -38,6 +38,7 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeLoongArchTarget() { initializeLoongArchMergeBaseOffsetOptPass(*PR); initializeLoongArchOptWInstrsPass(*PR); initializeLoongArchPreRAExpandPseudoPass(*PR); + initializeLoongArchExpandPseudoPass(*PR); initializeLoongArchDAGToDAGISelLegacyPass(*PR); } diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchBaseInfo.h b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchBaseInfo.h index 23699043b9926..833cd06261624 100644 --- a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchBaseInfo.h +++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchBaseInfo.h @@ -17,6 +17,7 @@ #include "MCTargetDesc/LoongArchMCTargetDesc.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/CodeGen/MachineOperand.h" #include "llvm/MC/MCInstrDesc.h" #include "llvm/TargetParser/SubtargetFeature.h" @@ -58,8 +59,31 @@ enum { MO_LE_ADD_R, MO_LE_LO_R, // TODO: Add more flags. + + // Used to differentiate between target-specific "direct" flags and "bitmask" + // flags. A machine operand can only have one "direct" flag, but can have + // multiple "bitmask" flags. + MO_DIRECT_FLAG_MASK = 0x3f, + + MO_RELAX = 0x40 }; +// Given a MachineOperand that may carry out "bitmask" flags, such as MO_RELAX, +// return LoongArch target-specific "direct" flags. +static inline unsigned getDirectFlags(const MachineOperand &MO) { + return MO.getTargetFlags() & MO_DIRECT_FLAG_MASK; +} + +// Add MO_RELAX "bitmask" flag when FeatureRelax is enabled. +static inline unsigned encodeFlags(unsigned Flags, bool Relax) { + return Flags | (Relax ? MO_RELAX : 0); +} + +// \returns true if the given MachineOperand has MO_RELAX "bitmask" flag. +static inline bool hasRelaxFlag(const MachineOperand &MO) { + return MO.getTargetFlags() & MO_RELAX; +} + // Target-specific flags of LAInst. // All definitions must match LoongArchInstrFormats.td. enum { diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCCodeEmitter.cpp b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCCodeEmitter.cpp index 04d57f0fe7457..02ec321857e57 100644 --- a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCCodeEmitter.cpp +++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCCodeEmitter.cpp @@ -249,6 +249,7 @@ LoongArchMCCodeEmitter::getExprOpValue(const MCInst &MI, const MCOperand &MO, break; case LoongArchMCExpr::VK_LoongArch_CALL36: FixupKind = LoongArch::fixup_loongarch_call36; + RelaxCandidate = true; break; case LoongArchMCExpr::VK_LoongArch_TLS_DESC_PC_HI20: FixupKind = LoongArch::fixup_loongarch_tls_desc_pc_hi20; diff --git a/llvm/test/CodeGen/LoongArch/linker-relaxation.ll b/llvm/test/CodeGen/LoongArch/linker-relaxation.ll new file mode 100644 index 0000000000000..2827a95547903 --- /dev/null +++ b/llvm/test/CodeGen/LoongArch/linker-relaxation.ll @@ -0,0 +1,102 @@ +; RUN: llc --mtriple=loongarch64 --filetype=obj -mattr=-relax \ +; RUN: --relocation-model=pic --code-model=medium < %s \ +; RUN: | llvm-readobj -r - | FileCheck --check-prefixes=CHECK-RELOC,PCALA-RELOC %s +; RUN: llc --mtriple=loongarch64 --filetype=obj -mattr=+relax \ +; RUN: --relocation-model=pic --code-model=medium < %s \ +; RUN: | llvm-readobj -r - | FileCheck --check-prefixes=CHECK-RELOC,RELAX %s + +; RUN: llc --mtriple=loongarch64 --filetype=obj -mattr=-relax --enable-tlsdesc \ +; RUN: --relocation-model=pic --code-model=medium < %s \ +; RUN: | llvm-readobj -r - | FileCheck --check-prefix=DESC-RELOC %s +; RUN: llc --mtriple=loongarch64 --filetype=obj -mattr=+relax --enable-tlsdesc \ +; RUN: --relocation-model=pic --code-model=medium < %s \ +; RUN: | llvm-readobj -r - | FileCheck --check-prefixes=DESC-RELOC,DESC-RELAX %s + +;; Check relocations when disable or enable linker relaxation. +;; This tests are also able to test for removing relax mask flags +;; after loongarch-merge-base-offset pass because no relax relocs +;; are emitted after being optimized by it. + +@g_e = external global i32 +@g_i = internal global i32 0 +@g_i1 = internal global i32 1 +@t_un = external thread_local global i32 +@t_ld = external thread_local(localdynamic) global i32 +@t_ie = external thread_local(initialexec) global i32 +@t_le = external thread_local(localexec) global i32 + +declare void @callee1() nounwind +declare dso_local void @callee2() nounwind +declare dso_local void @callee3() nounwind + +define ptr @caller() nounwind { +; RELAX: R_LARCH_ALIGN - 0x1C +; CHECK-RELOC: R_LARCH_GOT_PC_HI20 g_e 0x0 +; RELAX-NEXT: R_LARCH_RELAX - 0x0 +; CHECK-RELOC-NEXT: R_LARCH_GOT_PC_LO12 g_e 0x0 +; RELAX-NEXT: R_LARCH_RELAX - 0x0 +; PCALA-RELOC: R_LARCH_PCALA_HI20 .bss 0x0 +; RELAX-NEXT: R_LARCH_PCALA_HI20 g_i 0x0 +; PCALA-RELOC: R_LARCH_PCALA_LO12 .bss 0x0 +; RELAX-NEXT: R_LARCH_PCALA_LO12 g_i 0x0 +; CHECK-RELOC: R_LARCH_TLS_GD_PC_HI20 t_un 0x0 +; RELAX-NEXT: R_LARCH_RELAX - 0x0 +; CHECK-RELOC-NEXT: R_LARCH_GOT_PC_LO12 t_un 0x0 +; RELAX-NEXT: R_LARCH_RELAX - 0x0 +; CHECK-RELOC-NEXT: R_LARCH_CALL36 __tls_get_addr 0x0 +; RELAX-NEXT: R_LARCH_RELAX - 0x0 +; DESC-RELOC: R_LARCH_TLS_DESC_PC_HI20 t_un 0x0 +; DESC-RELAX: R_LARCH_RELAX - 0x0 +; DESC-RELOC-NEXT: R_LARCH_TLS_DESC_PC_LO12 t_un 0x0 +; DESC-RELAX-NEXT: R_LARCH_RELAX - 0x0 +; DESC-RELOC-NEXT: R_LARCH_TLS_DESC_LD t_un 0x0 +; DESC-RELAX-NEXT: R_LARCH_RELAX - 0x0 +; DESC-RELOC-NEXT: R_LARCH_TLS_DESC_CALL t_un 0x0 +; DESC-RELAX-NEXT: R_LARCH_RELAX - 0x0 +; CHECK-RELOC-NEXT: R_LARCH_TLS_LD_PC_HI20 t_ld 0x0 +; RELAX-NEXT: R_LARCH_RELAX - 0x0 +; CHECK-RELOC-NEXT: R_LARCH_GOT_PC_LO12 t_ld 0x0 +; RELAX-NEXT: R_LARCH_RELAX - 0x0 +; CHECK-RELOC-NEXT: R_LARCH_CALL36 __tls_get_addr 0x0 +; RELAX-NEXT: R_LARCH_RELAX - 0x0 +; DESC-RELOC-NEXT: R_LARCH_TLS_DESC_PC_HI20 t_ld 0x0 +; DESC-RELAX-NEXT: R_LARCH_RELAX - 0x0 +; DESC-RELOC-NEXT: R_LARCH_TLS_DESC_PC_LO12 t_ld 0x0 +; DESC-RELAX-NEXT: R_LARCH_RELAX - 0x0 +; DESC-RELOC-NEXT: R_LARCH_TLS_DESC_LD t_ld 0x0 +; DESC-RELAX-NEXT: R_LARCH_RELAX - 0x0 +; DESC-RELOC-NEXT: R_LARCH_TLS_DESC_CALL t_ld 0x0 +; DESC-RELAX-NEXT: R_LARCH_RELAX - 0x0 +; CHECK-RELOC-NEXT: R_LARCH_TLS_IE_PC_HI20 t_ie 0x0 +; RELAX-NEXT: R_LARCH_RELAX - 0x0 +; CHECK-RELOC-NEXT: R_LARCH_TLS_IE_PC_LO12 t_ie 0x0 +; RELAX-NEXT: R_LARCH_RELAX - 0x0 +; CHECK-RELOC-NEXT: R_LARCH_TLS_LE_HI20_R t_le 0x0 +; RELAX-NEXT: R_LARCH_RELAX - 0x0 +; CHECK-RELOC-NEXT: R_LARCH_TLS_LE_ADD_R t_le 0x0 +; RELAX-NEXT: R_LARCH_RELAX - 0x0 +; CHECK-RELOC-NEXT: R_LARCH_TLS_LE_LO12_R t_le 0x0 +; RELAX-NEXT: R_LARCH_RELAX - 0x0 +; CHECK-RELOC-NEXT: R_LARCH_CALL36 callee1 0x0 +; RELAX-NEXT: R_LARCH_RELAX - 0x0 +; CHECK-RELOC-NEXT: R_LARCH_CALL36 callee2 0x0 +; RELAX-NEXT: R_LARCH_RELAX - 0x0 +; CHECK-RELOC-NEXT: R_LARCH_CALL36 callee3 0x0 +; RELAX-NEXT: R_LARCH_RELAX - 0x0 +; PCALA-RELOC: R_LARCH_PCALA_HI20 .data 0x0 +; RELAX-NEXT: R_LARCH_PCALA_HI20 g_i1 0x0 +; RELAX-NEXT: R_LARCH_RELAX - 0x0 +; PCALA-RELOC: R_LARCH_PCALA_LO12 .data 0x0 +; RELAX-NEXT: R_LARCH_PCALA_LO12 g_i1 0x0 +; RELAX-NEXT: R_LARCH_RELAX - 0x0 + %a = load volatile i32, ptr @g_e + %b = load volatile i32, ptr @g_i + %c = load volatile i32, ptr @t_un + %d = load volatile i32, ptr @t_ld + %e = load volatile i32, ptr @t_ie + %f = load volatile i32, ptr @t_le + call i32 @callee1() + call i32 @callee2() + tail call i32 @callee3() + ret ptr @g_i1 +} diff --git a/llvm/test/CodeGen/LoongArch/mir-relax-flags.ll b/llvm/test/CodeGen/LoongArch/mir-relax-flags.ll new file mode 100644 index 0000000000000..b894de50eed29 --- /dev/null +++ b/llvm/test/CodeGen/LoongArch/mir-relax-flags.ll @@ -0,0 +1,64 @@ +; RUN: llc --mtriple=loongarch64 -mattr=+d,+relax --stop-after loongarch-prera-expand-pseudo \ +; RUN: --relocation-model=pic --code-model=medium %s -o %t.mir +; RUN: llc --mtriple=loongarch64 -mattr=+d,+relax --run-pass loongarch-prera-expand-pseudo \ +; RUN: --code-model=medium %t.mir -o - | FileCheck %s --check-prefixes=CHECK,MEDCALL +; RUN: llc --mtriple=loongarch64 -mattr=+d,+relax --run-pass loongarch-expand-pseudo \ +; RUN: --code-model=medium %t.mir -o - | FileCheck %s --check-prefixes=CHECK,CALL36 + +; RUN: llc --mtriple=loongarch64 -mattr=+d,+relax --stop-after loongarch-prera-expand-pseudo \ +; RUN: --relocation-model=pic --enable-tlsdesc --code-model=medium %s -o %t.desc.mir +; RUN: llc --mtriple=loongarch64 -mattr=+d,+relax --run-pass loongarch-prera-expand-pseudo \ +; RUN: --code-model=medium %t.desc.mir -o - | FileCheck %s --check-prefix=DESC + +;; Check target-flags after expand-pseudo pass. + +@g_e = external global i32 +@g_i = internal global i32 0 +@t_un = external thread_local global i32 +@t_ld = external thread_local(localdynamic) global i32 +@t_ie = external thread_local(initialexec) global i32 +@t_le = external thread_local(localexec) global i32 + +declare void @callee1() nounwind +declare dso_local void @callee2() nounwind +declare dso_local void @callee3() nounwind + +define void @caller() nounwind { +; CHECK: target-flags(loongarch-got-pc-hi, loongarch-relax) @g_e +; CHECK-NEXT: target-flags(loongarch-got-pc-lo, loongarch-relax) @g_e +; CHECK: target-flags(loongarch-pcrel-hi, loongarch-relax) @g_i +; CHECK-NEXT: target-flags(loongarch-pcrel-lo, loongarch-relax) @g_i +; CHECK: target-flags(loongarch-gd-pc-hi, loongarch-relax) @t_un +; CHECK-NEXT: target-flags(loongarch-got-pc-lo, loongarch-relax) @t_un +; DESC: target-flags(loongarch-desc-pc-hi, loongarch-relax) @t_un +; DESC-NEXT: target-flags(loongarch-desc-pc-lo, loongarch-relax) @t_un +; DESC-NEXT: target-flags(loongarch-desc-ld, loongarch-relax) @t_un +; DESC-NEXT: target-flags(loongarch-desc-call, loongarch-relax) @t_un +; CHECK: target-flags(loongarch-ld-pc-hi, loongarch-relax) @t_ld +; CHECK-NEXT: target-flags(loongarch-got-pc-lo, loongarch-relax) @t_ld +; DESC: target-flags(loongarch-desc-pc-hi, loongarch-relax) @t_ld +; DESC-NEXT: target-flags(loongarch-desc-pc-lo, loongarch-relax) @t_ld +; DESC-NEXT: target-flags(loongarch-desc-ld, loongarch-relax) @t_ld +; DESC-NEXT: target-flags(loongarch-desc-call, loongarch-relax) @t_ld +; CHECK: target-flags(loongarch-ie-pc-hi, loongarch-relax) @t_ie +; CHECK-NEXT: target-flags(loongarch-ie-pc-lo, loongarch-relax) @t_ie +; CHECK: target-flags(loongarch-le-hi-r) @t_le +; CHECK-NEXT: target-flags(loongarch-le-add-r) @t_le +; CHECK-NEXT: target-flags(loongarch-le-lo-r) @t_le +; MEDCALL: target-flags(loongarch-call-plt) @callee1 +; CALL36: target-flags(loongarch-call36) @callee1 +; MEDCALL: target-flags(loongarch-call) @callee2 +; CALL36: target-flags(loongarch-call36) @callee2 +; MEDCALL: target-flags(loongarch-call) @callee3 +; CALL36: target-flags(loongarch-call36) @callee3 + %a = load volatile i32, ptr @g_e + %b = load volatile i32, ptr @g_i + %c = load volatile i32, ptr @t_un + %d = load volatile i32, ptr @t_ld + %e = load volatile i32, ptr @t_ie + %f = load volatile i32, ptr @t_le + call i32 @callee1() + call i32 @callee2() + tail call i32 @callee3() + ret void +} diff --git a/llvm/test/CodeGen/LoongArch/mir-target-flags.ll b/llvm/test/CodeGen/LoongArch/mir-target-flags.ll index 3bc8a8d309586..51c2a19da80e3 100644 --- a/llvm/test/CodeGen/LoongArch/mir-target-flags.ll +++ b/llvm/test/CodeGen/LoongArch/mir-target-flags.ll @@ -1,7 +1,18 @@ -; RUN: llc --mtriple=loongarch64 -mattr=+d --stop-after loongarch-prera-expand-pseudo \ -; RUN: --relocation-model=pic %s -o %t.mir -; RUN: llc --mtriple=loongarch64 -mattr=+d --run-pass loongarch-prera-expand-pseudo \ +; RUN: llc --mtriple=loongarch64 -mattr=+d,-relax --stop-after loongarch-prera-expand-pseudo \ +; RUN: --relocation-model=pic --code-model=small %s -o %t.mir +; RUN: llc --mtriple=loongarch64 -mattr=+d,-relax --run-pass loongarch-prera-expand-pseudo \ ; RUN: %t.mir -o - | FileCheck %s +; RUN: llc --mtriple=loongarch64 -mattr=+d,-relax --stop-after loongarch-prera-expand-pseudo \ +; RUN: --relocation-model=pic --enable-tlsdesc --code-model=small %s -o %t.desc.mir +; RUN: llc --mtriple=loongarch64 -mattr=+d,-relax --run-pass loongarch-prera-expand-pseudo \ +; RUN: %t.desc.mir -o - | FileCheck %s --check-prefix=DESC + +; RUN: llc --mtriple=loongarch64 -mattr=+d,-relax --stop-after loongarch-prera-expand-pseudo \ +; RUN: --relocation-model=pic --code-model=medium %s -o %t.med.mir +; RUN: llc --mtriple=loongarch64 -mattr=+d,-relax --run-pass loongarch-prera-expand-pseudo \ +; RUN: --code-model=medium %t.med.mir -o - | FileCheck %s +; RUN: llc --mtriple=loongarch64 -mattr=+d,-relax --run-pass loongarch-expand-pseudo \ +; RUN: --code-model=medium %t.med.mir -o - | FileCheck %s --check-prefixes=CALL36 ;; This tests the LoongArch-specific serialization and deserialization of ;; `target-flags(...)` @@ -15,6 +26,7 @@ declare void @callee1() nounwind declare dso_local void @callee2() nounwind +declare dso_local void @callee3() nounwind define void @caller() nounwind { ; CHECK-LABEL: name: caller @@ -24,15 +36,27 @@ define void @caller() nounwind { ; CHECK-NEXT: target-flags(loongarch-pcrel-lo) @g_i ; CHECK: target-flags(loongarch-gd-pc-hi) @t_un ; CHECK-NEXT: target-flags(loongarch-got-pc-lo) @t_un +; DESC: target-flags(loongarch-desc-pc-hi) @t_un +; DESC-NEXT: target-flags(loongarch-desc-pc-lo) @t_un +; DESC-NEXT: target-flags(loongarch-desc-ld) @t_un +; DESC-NEXT: target-flags(loongarch-desc-call) @t_un ; CHECK: target-flags(loongarch-ld-pc-hi) @t_ld ; CHECK-NEXT: target-flags(loongarch-got-pc-lo) @t_ld +; DESC: target-flags(loongarch-desc-pc-hi) @t_ld +; DESC-NEXT: target-flags(loongarch-desc-pc-lo) @t_ld +; DESC-NEXT: target-flags(loongarch-desc-ld) @t_ld +; DESC-NEXT: target-flags(loongarch-desc-call) @t_ld ; CHECK: target-flags(loongarch-ie-pc-hi) @t_ie ; CHECK-NEXT: target-flags(loongarch-ie-pc-lo) @t_ie ; CHECK: target-flags(loongarch-le-hi-r) @t_le ; CHECK-NEXT: target-flags(loongarch-le-add-r) @t_le ; CHECK-NEXT: target-flags(loongarch-le-lo-r) @t_le ; CHECK: target-flags(loongarch-call-plt) @callee1 +; CALL36: target-flags(loongarch-call36) @callee1 ; CHECK: target-flags(loongarch-call) @callee2 +; CALL36: target-flags(loongarch-call36) @callee2 +; CHECK: target-flags(loongarch-call) @callee3 +; CALL36: target-flags(loongarch-call36) @callee3 %a = load volatile i32, ptr @g_e %b = load volatile i32, ptr @g_i %c = load volatile i32, ptr @t_un @@ -41,5 +65,6 @@ define void @caller() nounwind { %f = load volatile i32, ptr @t_le call i32 @callee1() call i32 @callee2() + tail call i32 @callee3() ret void }