Skip to content

Commit

Permalink
[LoongArch] Emit R_LARCH_RELAX when expanding some LoadAddress (llvm#…
Browse files Browse the repository at this point in the history
…72961)

Emit relax relocs when expand non-large la.pcrel and non-large la.got on
llvm-mc stage, which like what does on GAS.
1, la.pcrel -> PCALA_HI20 + RELAX + PCALA_LO12 + RELAX
2, la.got -> GOT_PC_HI20 + RELAX + GOT_PC_LO12 + RELAX
  • Loading branch information
MQ-mengqing authored Dec 27, 2023
1 parent 5a402c5 commit b3ef8dc
Show file tree
Hide file tree
Showing 7 changed files with 115 additions and 27 deletions.
12 changes: 7 additions & 5 deletions llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ class LoongArchAsmParser : public MCTargetAsmParser {
// "emitLoadAddress*" functions.
void emitLAInstSeq(MCRegister DestReg, MCRegister TmpReg,
const MCExpr *Symbol, SmallVectorImpl<Inst> &Insts,
SMLoc IDLoc, MCStreamer &Out);
SMLoc IDLoc, MCStreamer &Out, bool RelaxHint = false);

// Helper to emit pseudo instruction "la.abs $rd, sym".
void emitLoadAddressAbs(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);
Expand Down Expand Up @@ -748,12 +748,14 @@ bool LoongArchAsmParser::ParseInstruction(ParseInstructionInfo &Info,
void LoongArchAsmParser::emitLAInstSeq(MCRegister DestReg, MCRegister TmpReg,
const MCExpr *Symbol,
SmallVectorImpl<Inst> &Insts,
SMLoc IDLoc, MCStreamer &Out) {
SMLoc IDLoc, MCStreamer &Out,
bool RelaxHint) {
MCContext &Ctx = getContext();
for (LoongArchAsmParser::Inst &Inst : Insts) {
unsigned Opc = Inst.Opc;
LoongArchMCExpr::VariantKind VK = Inst.VK;
const LoongArchMCExpr *LE = LoongArchMCExpr::create(Symbol, VK, Ctx);
const LoongArchMCExpr *LE =
LoongArchMCExpr::create(Symbol, VK, Ctx, RelaxHint);
switch (Opc) {
default:
llvm_unreachable("unexpected opcode");
Expand Down Expand Up @@ -854,7 +856,7 @@ void LoongArchAsmParser::emitLoadAddressPcrel(MCInst &Inst, SMLoc IDLoc,
Insts.push_back(
LoongArchAsmParser::Inst(ADDI, LoongArchMCExpr::VK_LoongArch_PCALA_LO12));

emitLAInstSeq(DestReg, DestReg, Symbol, Insts, IDLoc, Out);
emitLAInstSeq(DestReg, DestReg, Symbol, Insts, IDLoc, Out, true);
}

void LoongArchAsmParser::emitLoadAddressPcrelLarge(MCInst &Inst, SMLoc IDLoc,
Expand Down Expand Up @@ -900,7 +902,7 @@ void LoongArchAsmParser::emitLoadAddressGot(MCInst &Inst, SMLoc IDLoc,
Insts.push_back(
LoongArchAsmParser::Inst(LD, LoongArchMCExpr::VK_LoongArch_GOT_PC_LO12));

emitLAInstSeq(DestReg, DestReg, Symbol, Insts, IDLoc, Out);
emitLAInstSeq(DestReg, DestReg, Symbol, Insts, IDLoc, Out, true);
}

void LoongArchAsmParser::emitLoadAddressGotLarge(MCInst &Inst, SMLoc IDLoc,
Expand Down
13 changes: 13 additions & 0 deletions llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCCodeEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "llvm/MC/MCInstBuilder.h"
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/EndianStream.h"

Expand Down Expand Up @@ -120,12 +121,15 @@ LoongArchMCCodeEmitter::getExprOpValue(const MCInst &MI, const MCOperand &MO,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
assert(MO.isExpr() && "getExprOpValue expects only expressions");
bool RelaxCandidate = false;
bool EnableRelax = STI.hasFeature(LoongArch::FeatureRelax);
const MCExpr *Expr = MO.getExpr();
MCExpr::ExprKind Kind = Expr->getKind();
LoongArch::Fixups FixupKind = LoongArch::fixup_loongarch_invalid;
if (Kind == MCExpr::Target) {
const LoongArchMCExpr *LAExpr = cast<LoongArchMCExpr>(Expr);

RelaxCandidate = LAExpr->getRelaxHint();
switch (LAExpr->getKind()) {
case LoongArchMCExpr::VK_LoongArch_None:
case LoongArchMCExpr::VK_LoongArch_Invalid:
Expand Down Expand Up @@ -270,6 +274,15 @@ LoongArchMCCodeEmitter::getExprOpValue(const MCInst &MI, const MCOperand &MO,

Fixups.push_back(
MCFixup::create(0, Expr, MCFixupKind(FixupKind), MI.getLoc()));

// Emit an R_LARCH_RELAX if linker relaxation is enabled and LAExpr has relax
// hint.
if (EnableRelax && RelaxCandidate) {
const MCConstantExpr *Dummy = MCConstantExpr::create(0, Ctx);
Fixups.push_back(MCFixup::create(
0, Dummy, MCFixupKind(LoongArch::fixup_loongarch_relax), MI.getLoc()));
}

return 0;
}

Expand Down
7 changes: 4 additions & 3 deletions llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,10 @@ using namespace llvm;

#define DEBUG_TYPE "loongarch-mcexpr"

const LoongArchMCExpr *
LoongArchMCExpr::create(const MCExpr *Expr, VariantKind Kind, MCContext &Ctx) {
return new (Ctx) LoongArchMCExpr(Expr, Kind);
const LoongArchMCExpr *LoongArchMCExpr::create(const MCExpr *Expr,
VariantKind Kind, MCContext &Ctx,
bool Hint) {
return new (Ctx) LoongArchMCExpr(Expr, Kind, Hint);
}

void LoongArchMCExpr::printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const {
Expand Down
8 changes: 5 additions & 3 deletions llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCExpr.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,16 +67,18 @@ class LoongArchMCExpr : public MCTargetExpr {
private:
const MCExpr *Expr;
const VariantKind Kind;
const bool RelaxHint;

explicit LoongArchMCExpr(const MCExpr *Expr, VariantKind Kind)
: Expr(Expr), Kind(Kind) {}
explicit LoongArchMCExpr(const MCExpr *Expr, VariantKind Kind, bool Hint)
: Expr(Expr), Kind(Kind), RelaxHint(Hint) {}

public:
static const LoongArchMCExpr *create(const MCExpr *Expr, VariantKind Kind,
MCContext &Ctx);
MCContext &Ctx, bool Hint = false);

VariantKind getKind() const { return Kind; }
const MCExpr *getSubExpr() const { return Expr; }
bool getRelaxHint() const { return RelaxHint; }

void printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const override;
bool evaluateAsRelocatableImpl(MCValue &Res, const MCAsmLayout *Layout,
Expand Down
84 changes: 73 additions & 11 deletions llvm/test/MC/LoongArch/Macros/macros-la.s
Original file line number Diff line number Diff line change
@@ -1,66 +1,128 @@
# RUN: llvm-mc --triple=loongarch64 %s | FileCheck %s
# RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=-relax %s -o %t
# RUN: llvm-readobj -r %t | FileCheck %s --check-prefix=RELOC
# RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax %s -o %t.relax
# RUN: llvm-readobj -r %t.relax | FileCheck %s --check-prefixes=RELOC,RELAX

# RELOC: Relocations [
# RELOC-NEXT: Section ({{.*}}) .rela.text {

la.abs $a0, sym_abs
# CHECK: lu12i.w $a0, %abs_hi20(sym_abs)
# CHECK-NEXT: ori $a0, $a0, %abs_lo12(sym_abs)
# CHECK-NEXT: lu32i.d $a0, %abs64_lo20(sym_abs)
# CHECK-NEXT: lu52i.d $a0, $a0, %abs64_hi12(sym_abs)
# CHECK-EMPTY:
# RELOC-NEXT: R_LARCH_ABS_HI20 sym_abs 0x0
# RELOC-NEXT: R_LARCH_ABS_LO12 sym_abs 0x0
# RELOC-NEXT: R_LARCH_ABS64_LO20 sym_abs 0x0
# RELOC-NEXT: R_LARCH_ABS64_HI12 sym_abs 0x0

la.pcrel $a0, sym_pcrel
# CHECK: pcalau12i $a0, %pc_hi20(sym_pcrel)
# CHECK-NEXT: pcalau12i $a0, %pc_hi20(sym_pcrel)
# CHECK-NEXT: addi.d $a0, $a0, %pc_lo12(sym_pcrel)
# CHECK-EMPTY:
# RELOC-NEXT: R_LARCH_PCALA_HI20 sym_pcrel 0x0
# RELAX-NEXT: R_LARCH_RELAX - 0x0
# RELOC-NEXT: R_LARCH_PCALA_LO12 sym_pcrel 0x0
# RELAX-NEXT: R_LARCH_RELAX - 0x0

la.pcrel $a0, $a1, sym_pcrel_large
# CHECK: pcalau12i $a0, %pc_hi20(sym_pcrel_large)
# CHECK-NEXT: pcalau12i $a0, %pc_hi20(sym_pcrel_large)
# CHECK-NEXT: addi.d $a1, $zero, %pc_lo12(sym_pcrel_large)
# CHECK-NEXT: lu32i.d $a1, %pc64_lo20(sym_pcrel_large)
# CHECK-NEXT: lu52i.d $a1, $a1, %pc64_hi12(sym_pcrel_large)
# CHECK-NEXT: add.d $a0, $a0, $a1
# CHECK-EMPTY:
# RELOC-NEXT: R_LARCH_PCALA_HI20 sym_pcrel_large 0x0
# RELOC-NEXT: R_LARCH_PCALA_LO12 sym_pcrel_large 0x0
# RELOC-NEXT: R_LARCH_PCALA64_LO20 sym_pcrel_large 0x0
# RELOC-NEXT: R_LARCH_PCALA64_HI12 sym_pcrel_large 0x0

la.got $a0, sym_got
# CHECK: pcalau12i $a0, %got_pc_hi20(sym_got)
# CHECK-NEXT: pcalau12i $a0, %got_pc_hi20(sym_got)
# CHECK-NEXT: ld.d $a0, $a0, %got_pc_lo12(sym_got)
# CHECK-EMPTY:
# RELOC-NEXT: R_LARCH_GOT_PC_HI20 sym_got 0x0
# RELAX-NEXT: R_LARCH_RELAX - 0x0
# RELOC-NEXT: R_LARCH_GOT_PC_LO12 sym_got 0x0
# RELAX-NEXT: R_LARCH_RELAX - 0x0

la.got $a0, $a1, sym_got_large
# CHECK: pcalau12i $a0, %got_pc_hi20(sym_got_large)
# CHECK-NEXT: pcalau12i $a0, %got_pc_hi20(sym_got_large)
# CHECK-NEXT: addi.d $a1, $zero, %got_pc_lo12(sym_got_large)
# CHECK-NEXT: lu32i.d $a1, %got64_pc_lo20(sym_got_large)
# CHECK-NEXT: lu52i.d $a1, $a1, %got64_pc_hi12(sym_got_large)
# CHECK-NEXT: ldx.d $a0, $a0, $a1
# CHECK-EMPTY:
# RELOC-NEXT: R_LARCH_GOT_PC_HI20 sym_got_large 0x0
# RELOC-NEXT: R_LARCH_GOT_PC_LO12 sym_got_large 0x0
# RELOC-NEXT: R_LARCH_GOT64_PC_LO20 sym_got_large 0x0
# RELOC-NEXT: R_LARCH_GOT64_PC_HI12 sym_got_large 0x0

la.tls.le $a0, sym_le
# CHECK: lu12i.w $a0, %le_hi20(sym_le)
# CHECK-NEXT: lu12i.w $a0, %le_hi20(sym_le)
# CHECK-NEXT: ori $a0, $a0, %le_lo12(sym_le)
# CHECK-EMPTY:
# RELOC-NEXT: R_LARCH_TLS_LE_HI20 sym_le 0x0
# RELOC-NEXT: R_LARCH_TLS_LE_LO12 sym_le 0x0

la.tls.ie $a0, sym_ie
# CHECK: pcalau12i $a0, %ie_pc_hi20(sym_ie)
# CHECK-NEXT: pcalau12i $a0, %ie_pc_hi20(sym_ie)
# CHECK-NEXT: ld.d $a0, $a0, %ie_pc_lo12(sym_ie)
# CHECK-EMPTY:
# RELOC-NEXT: R_LARCH_TLS_IE_PC_HI20 sym_ie 0x0
# RELOC-NEXT: R_LARCH_TLS_IE_PC_LO12 sym_ie 0x0

la.tls.ie $a0, $a1, sym_ie_large
# CHECK: pcalau12i $a0, %ie_pc_hi20(sym_ie_large)
# CHECK-NEXT: pcalau12i $a0, %ie_pc_hi20(sym_ie_large)
# CHECK-NEXT: addi.d $a1, $zero, %ie_pc_lo12(sym_ie_large)
# CHECK-NEXT: lu32i.d $a1, %ie64_pc_lo20(sym_ie_large)
# CHECK-NEXT: lu52i.d $a1, $a1, %ie64_pc_hi12(sym_ie_large)
# CHECK-NEXT: ldx.d $a0, $a0, $a1
# CHECK-EMPTY:
# RELOC-NEXT: R_LARCH_TLS_IE_PC_HI20 sym_ie_large 0x0
# RELOC-NEXT: R_LARCH_TLS_IE_PC_LO12 sym_ie_large 0x0
# RELOC-NEXT: R_LARCH_TLS_IE64_PC_LO20 sym_ie_large 0x0
# RELOC-NEXT: R_LARCH_TLS_IE64_PC_HI12 sym_ie_large 0x0

la.tls.ld $a0, sym_ld
# CHECK: pcalau12i $a0, %ld_pc_hi20(sym_ld)
# CHECK-NEXT: pcalau12i $a0, %ld_pc_hi20(sym_ld)
# CHECK-NEXT: addi.d $a0, $a0, %got_pc_lo12(sym_ld)
# CHECK-EMPTY:
# RELOC-NEXT: R_LARCH_TLS_LD_PC_HI20 sym_ld 0x0
# RELOC-NEXT: R_LARCH_GOT_PC_LO12 sym_ld 0x0

la.tls.ld $a0, $a1, sym_ld_large
# CHECK: pcalau12i $a0, %ld_pc_hi20(sym_ld_large)
# CHECK-NEXT: pcalau12i $a0, %ld_pc_hi20(sym_ld_large)
# CHECK-NEXT: addi.d $a1, $zero, %got_pc_lo12(sym_ld_large)
# CHECK-NEXT: lu32i.d $a1, %got64_pc_lo20(sym_ld_large)
# CHECK-NEXT: lu52i.d $a1, $a1, %got64_pc_hi12(sym_ld_large)
# CHECK-NEXT: add.d $a0, $a0, $a1
# CHECK-EMPTY:
# RELOC-NEXT: R_LARCH_TLS_LD_PC_HI20 sym_ld_large 0x0
# RELOC-NEXT: R_LARCH_GOT_PC_LO12 sym_ld_large 0x0
# RELOC-NEXT: R_LARCH_GOT64_PC_LO20 sym_ld_large 0x0
# RELOC-NEXT: R_LARCH_GOT64_PC_HI12 sym_ld_large 0x0

la.tls.gd $a0, sym_gd
# CHECK: pcalau12i $a0, %gd_pc_hi20(sym_gd)
# CHECK-NEXT: pcalau12i $a0, %gd_pc_hi20(sym_gd)
# CHECK-NEXT: addi.d $a0, $a0, %got_pc_lo12(sym_gd)
# CHECK-EMPTY:
# RELOC-NEXT: R_LARCH_TLS_GD_PC_HI20 sym_gd 0x0
# RELOC-NEXT: R_LARCH_GOT_PC_LO12 sym_gd 0x0

la.tls.gd $a0, $a1, sym_gd_large
# CHECK: pcalau12i $a0, %gd_pc_hi20(sym_gd_large)
# CHECK-NEXT: pcalau12i $a0, %gd_pc_hi20(sym_gd_large)
# CHECK-NEXT: addi.d $a1, $zero, %got_pc_lo12(sym_gd_large)
# CHECK-NEXT: lu32i.d $a1, %got64_pc_lo20(sym_gd_large)
# CHECK-NEXT: lu52i.d $a1, $a1, %got64_pc_hi12(sym_gd_large)
# CHECK-NEXT: add.d $a0, $a0, $a1
# CHECK-EMPTY:
# RELOC-NEXT: R_LARCH_TLS_GD_PC_HI20 sym_gd_large 0x0
# RELOC-NEXT: R_LARCH_GOT_PC_LO12 sym_gd_large 0x0
# RELOC-NEXT: R_LARCH_GOT64_PC_LO20 sym_gd_large 0x0
# RELOC-NEXT: R_LARCH_GOT64_PC_HI12 sym_gd_large 0x0

# RELOC-NEXT: }
# RELOC-NEXT: ]
2 changes: 1 addition & 1 deletion llvm/test/MC/LoongArch/Misc/subsection.s
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# RUN: not llvm-mc --filetype=obj --triple=loongarch64 --mattr=-relax %s -o /dev/null 2>&1 | FileCheck %s --check-prefixes=ERR,NORELAX --implicit-check-not=error:
## TODO: not llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax %s -o /dev/null 2>&1 | FileCheck %s --check-prefixes=ERR,RELAX --implicit-check-not=error:
# RUN: not llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax %s -o /dev/null 2>&1 | FileCheck %s --check-prefixes=ERR,RELAX --implicit-check-not=error:

a:
nop
Expand Down
16 changes: 12 additions & 4 deletions llvm/test/MC/LoongArch/Relocations/relax-addsub.s
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@
# RELAX: Relocations [
# RELAX-NEXT: Section ({{.*}}) .rela.text {
# RELAX-NEXT: 0x10 R_LARCH_PCALA_HI20 .L1 0x0
# RELAX-NEXT: 0x10 R_LARCH_RELAX - 0x0
# RELAX-NEXT: 0x14 R_LARCH_PCALA_LO12 .L1 0x0
# RELAX-NEXT: 0x14 R_LARCH_RELAX - 0x0
# RELAX-NEXT: }
# RELAX-NEXT: Section ({{.*}}) .rela.data {
# RELAX-NEXT: 0xF R_LARCH_ADD8 .L3 0x0
Expand All @@ -29,13 +31,21 @@
# RELAX-NEXT: 0x12 R_LARCH_SUB32 .L2 0x0
# RELAX-NEXT: 0x16 R_LARCH_ADD64 .L3 0x0
# RELAX-NEXT: 0x16 R_LARCH_SUB64 .L2 0x0
# RELAX-NEXT: 0x1E R_LARCH_ADD8 .L4 0x0
# RELAX-NEXT: 0x1E R_LARCH_SUB8 .L3 0x0
# RELAX-NEXT: 0x1F R_LARCH_ADD16 .L4 0x0
# RELAX-NEXT: 0x1F R_LARCH_SUB16 .L3 0x0
# RELAX-NEXT: 0x21 R_LARCH_ADD32 .L4 0x0
# RELAX-NEXT: 0x21 R_LARCH_SUB32 .L3 0x0
# RELAX-NEXT: 0x25 R_LARCH_ADD64 .L4 0x0
# RELAX-NEXT: 0x25 R_LARCH_SUB64 .L3 0x0
# RELAX-NEXT: }
# RELAX-NEXT: ]

# RELAX: Hex dump of section '.data':
# RELAX-NEXT: 0x00000000 04040004 00000004 00000000 00000000
# RELAX-NEXT: 0x00000010 00000000 00000000 00000000 00000808
# RELAX-NEXT: 0x00000020 00080000 00080000 00000000 00
# RELAX-NEXT: 0x00000010 00000000 00000000 00000000 00000000
# RELAX-NEXT: 0x00000020 00000000 00000000 00000000 00

.text
.L1:
Expand All @@ -60,8 +70,6 @@
.short .L3 - .L2
.word .L3 - .L2
.dword .L3 - .L2
## TODO
## With relaxation, emit relocs because la.pcrel is a linker-relaxable inst.
.byte .L4 - .L3
.short .L4 - .L3
.word .L4 - .L3
Expand Down

0 comments on commit b3ef8dc

Please sign in to comment.