Skip to content

Commit 87f6adc

Browse files
MQ-mengqingAmi-zhang
authored andcommitted
[LoongArch] Insert nops and emit align reloc when handle alignment directive (llvm#72962)
Refer to RISCV, we will fix up the alignment if linker relaxation changes code size and breaks alignment. Insert enough Nops and emit R_LARCH_ALIGN relocation type so that linker could satisfy the alignment by removing Nops. It does so only in sections with the SHF_EXECINSTR flag. In LoongArch psABI v2.30, R_LARCH_ALIGN requires symbol index. The lowest 8 bits of addend represent alignment and the other bits of addend represent the maximum number of bytes to emit. (cherry picked from commit c51ab48) Change-Id: Iba30702c9dda378acfae0b1f1134926fa838a368
1 parent 286c92a commit 87f6adc

File tree

7 files changed

+205
-4
lines changed

7 files changed

+205
-4
lines changed

llvm/lib/MC/MCExpr.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -711,7 +711,7 @@ static void AttemptToFoldSymbolOffsetDifference(
711711
if (DF) {
712712
Displacement += DF->getContents().size();
713713
} else if (auto *AF = dyn_cast<MCAlignFragment>(FI);
714-
AF && Layout &&
714+
AF && Layout && AF->hasEmitNops() &&
715715
!Asm->getBackend().shouldInsertExtraNopBytesForCodeAlign(
716716
*AF, Count)) {
717717
Displacement += Asm->computeFragmentSize(*Layout, *AF);

llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchAsmBackend.cpp

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,13 @@
1717
#include "llvm/MC/MCAssembler.h"
1818
#include "llvm/MC/MCContext.h"
1919
#include "llvm/MC/MCELFObjectWriter.h"
20+
#include "llvm/MC/MCExpr.h"
21+
#include "llvm/MC/MCSection.h"
2022
#include "llvm/MC/MCValue.h"
2123
#include "llvm/Support/Endian.h"
2224
#include "llvm/Support/EndianStream.h"
2325
#include "llvm/Support/LEB128.h"
26+
#include "llvm/Support/MathExtras.h"
2427

2528
#define DEBUG_TYPE "loongarch-asmbackend"
2629

@@ -177,6 +180,70 @@ void LoongArchAsmBackend::applyFixup(const MCAssembler &Asm,
177180
}
178181
}
179182

183+
// Linker relaxation may change code size. We have to insert Nops
184+
// for .align directive when linker relaxation enabled. So then Linker
185+
// could satisfy alignment by removing Nops.
186+
// The function returns the total Nops Size we need to insert.
187+
bool LoongArchAsmBackend::shouldInsertExtraNopBytesForCodeAlign(
188+
const MCAlignFragment &AF, unsigned &Size) {
189+
// Calculate Nops Size only when linker relaxation enabled.
190+
if (!AF.getSubtargetInfo()->hasFeature(LoongArch::FeatureRelax))
191+
return false;
192+
193+
// Ignore alignment if MaxBytesToEmit is less than the minimum Nop size.
194+
const unsigned MinNopLen = 4;
195+
if (AF.getMaxBytesToEmit() < MinNopLen)
196+
return false;
197+
Size = AF.getAlignment().value() - MinNopLen;
198+
return AF.getAlignment() > MinNopLen;
199+
}
200+
201+
// We need to insert R_LARCH_ALIGN relocation type to indicate the
202+
// position of Nops and the total bytes of the Nops have been inserted
203+
// when linker relaxation enabled.
204+
// The function inserts fixup_loongarch_align fixup which eventually will
205+
// transfer to R_LARCH_ALIGN relocation type.
206+
// The improved R_LARCH_ALIGN requires symbol index. The lowest 8 bits of
207+
// addend represent alignment and the other bits of addend represent the
208+
// maximum number of bytes to emit. The maximum number of bytes is zero
209+
// means ignore the emit limit.
210+
bool LoongArchAsmBackend::shouldInsertFixupForCodeAlign(
211+
MCAssembler &Asm, const MCAsmLayout &Layout, MCAlignFragment &AF) {
212+
// Insert the fixup only when linker relaxation enabled.
213+
if (!AF.getSubtargetInfo()->hasFeature(LoongArch::FeatureRelax))
214+
return false;
215+
216+
// Calculate total Nops we need to insert. If there are none to insert
217+
// then simply return.
218+
unsigned Count;
219+
if (!shouldInsertExtraNopBytesForCodeAlign(AF, Count))
220+
return false;
221+
222+
MCSection *Sec = AF.getParent();
223+
MCContext &Ctx = Asm.getContext();
224+
const MCExpr *Dummy = MCConstantExpr::create(0, Ctx);
225+
// Create fixup_loongarch_align fixup.
226+
MCFixup Fixup =
227+
MCFixup::create(0, Dummy, MCFixupKind(LoongArch::fixup_loongarch_align));
228+
const MCSymbolRefExpr *MCSym = getSecToAlignSym()[Sec];
229+
if (MCSym == nullptr) {
230+
// Create a symbol and make the value of symbol is zero.
231+
MCSymbol *Sym = Ctx.createNamedTempSymbol("la-relax-align");
232+
Sym->setFragment(&*Sec->getBeginSymbol()->getFragment());
233+
Asm.registerSymbol(*Sym);
234+
MCSym = MCSymbolRefExpr::create(Sym, Ctx);
235+
getSecToAlignSym()[Sec] = MCSym;
236+
}
237+
238+
uint64_t FixedValue = 0;
239+
unsigned Lo = Log2_64(Count) + 1;
240+
unsigned Hi = AF.getMaxBytesToEmit() >= Count ? 0 : AF.getMaxBytesToEmit();
241+
MCValue Value = MCValue::get(MCSym, nullptr, Hi << 8 | Lo);
242+
Asm.getWriter().recordRelocation(Asm, Layout, &AF, Fixup, Value, FixedValue);
243+
244+
return true;
245+
}
246+
180247
bool LoongArchAsmBackend::shouldForceRelocation(const MCAssembler &Asm,
181248
const MCFixup &Fixup,
182249
const MCValue &Target) {

llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchAsmBackend.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717
#include "MCTargetDesc/LoongArchFixupKinds.h"
1818
#include "MCTargetDesc/LoongArchMCTargetDesc.h"
1919
#include "llvm/MC/MCAsmBackend.h"
20+
#include "llvm/MC/MCExpr.h"
2021
#include "llvm/MC/MCFixupKindInfo.h"
22+
#include "llvm/MC/MCSection.h"
2123
#include "llvm/MC/MCSubtargetInfo.h"
2224

2325
namespace llvm {
@@ -27,6 +29,7 @@ class LoongArchAsmBackend : public MCAsmBackend {
2729
uint8_t OSABI;
2830
bool Is64Bit;
2931
const MCTargetOptions &TargetOptions;
32+
DenseMap<MCSection *, const MCSymbolRefExpr *> SecToAlignSym;
3033

3134
public:
3235
LoongArchAsmBackend(const MCSubtargetInfo &STI, uint8_t OSABI, bool Is64Bit,
@@ -45,6 +48,15 @@ class LoongArchAsmBackend : public MCAsmBackend {
4548
uint64_t Value, bool IsResolved,
4649
const MCSubtargetInfo *STI) const override;
4750

51+
// Return Size with extra Nop Bytes for alignment directive in code section.
52+
bool shouldInsertExtraNopBytesForCodeAlign(const MCAlignFragment &AF,
53+
unsigned &Size) override;
54+
55+
// Insert target specific fixup type for alignment directive in code section.
56+
bool shouldInsertFixupForCodeAlign(MCAssembler &Asm,
57+
const MCAsmLayout &Layout,
58+
MCAlignFragment &AF) override;
59+
4860
bool shouldForceRelocation(const MCAssembler &Asm, const MCFixup &Fixup,
4961
const MCValue &Target) override;
5062

@@ -79,6 +91,9 @@ class LoongArchAsmBackend : public MCAsmBackend {
7991
std::unique_ptr<MCObjectTargetWriter>
8092
createObjectTargetWriter() const override;
8193
const MCTargetOptions &getTargetOptions() const { return TargetOptions; }
94+
DenseMap<MCSection *, const MCSymbolRefExpr *> &getSecToAlignSym() {
95+
return SecToAlignSym;
96+
}
8297
};
8398
} // end namespace llvm
8499

llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchFixupKinds.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,9 @@ enum Fixups {
108108
// 20-bit fixup corresponding to %gd_hi20(foo) for instruction lu12i.w.
109109
fixup_loongarch_tls_gd_hi20,
110110
// Generate an R_LARCH_RELAX which indicates the linker may relax here.
111-
fixup_loongarch_relax = FirstLiteralRelocationKind + ELF::R_LARCH_RELAX
111+
fixup_loongarch_relax = FirstLiteralRelocationKind + ELF::R_LARCH_RELAX,
112+
// Generate an R_LARCH_ALIGN which indicates the linker may fixup align here.
113+
fixup_loongarch_align = FirstLiteralRelocationKind + ELF::R_LARCH_ALIGN,
112114
};
113115
} // end namespace LoongArch
114116
} // end namespace llvm
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
## A label difference separated by an alignment directive, when the
2+
## referenced symbols are in a non-executable section with instructions,
3+
## should generate ADD/SUB relocations.
4+
## https://github.com/llvm/llvm-project/pull/76552
5+
6+
# RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax %s \
7+
# RUN: | llvm-readobj -r - | FileCheck --check-prefixes=CHECK,RELAX %s
8+
# RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=-relax %s \
9+
# RUN: | llvm-readobj -r - | FileCheck %s
10+
11+
.section ".dummy", "a"
12+
.L1:
13+
la.pcrel $t0, sym
14+
.p2align 3
15+
.L2:
16+
.dword .L2 - .L1
17+
18+
# CHECK: Relocations [
19+
# CHECK-NEXT: Section ({{.*}}) .rela.dummy {
20+
# CHECK-NEXT: 0x0 R_LARCH_PCALA_HI20 sym 0x0
21+
# RELAX-NEXT: 0x0 R_LARCH_RELAX - 0x0
22+
# CHECK-NEXT: 0x4 R_LARCH_PCALA_LO12 sym 0x0
23+
# RELAX-NEXT: 0x4 R_LARCH_RELAX - 0x0
24+
# RELAX-NEXT: 0x8 R_LARCH_ADD64 .L2 0x0
25+
# RELAX-NEXT: 0x8 R_LARCH_SUB64 .L1 0x0
26+
# CHECK-NEXT: }
27+
# CHECK-NEXT: ]

llvm/test/MC/LoongArch/Relocations/relax-addsub.s

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,23 @@
2828

2929
# RELAX: Relocations [
3030
# RELAX-NEXT: Section ({{.*}}) .rela.text {
31+
# RELAX-NEXT: 0x4 R_LARCH_ALIGN {{.*}} 0x4
3132
# RELAX-NEXT: 0x10 R_LARCH_PCALA_HI20 .L1 0x0
3233
# RELAX-NEXT: 0x10 R_LARCH_RELAX - 0x0
3334
# RELAX-NEXT: 0x14 R_LARCH_PCALA_LO12 .L1 0x0
3435
# RELAX-NEXT: 0x14 R_LARCH_RELAX - 0x0
3536
# RELAX-NEXT: }
3637
# RELAX-NEXT: Section ({{.*}}) .rela.data {
38+
# RELAX-NEXT: 0x10 R_LARCH_ADD8 .L3 0x0
39+
# RELAX-NEXT: 0x10 R_LARCH_SUB8 .L2 0x0
40+
# RELAX-NEXT: 0x11 R_LARCH_ADD16 .L3 0x0
41+
# RELAX-NEXT: 0x11 R_LARCH_SUB16 .L2 0x0
42+
# RELAX-NEXT: 0x13 R_LARCH_ADD32 .L3 0x0
43+
# RELAX-NEXT: 0x13 R_LARCH_SUB32 .L2 0x0
44+
# RELAX-NEXT: 0x17 R_LARCH_ADD64 .L3 0x0
45+
# RELAX-NEXT: 0x17 R_LARCH_SUB64 .L2 0x0
46+
# RELAX-NEXT: 0x1F R_LARCH_ADD_ULEB128 .L3 0x0
47+
# RELAX-NEXT: 0x1F R_LARCH_SUB_ULEB128 .L2 0x0
3748
# RELAX-NEXT: 0x20 R_LARCH_ADD8 .L4 0x0
3849
# RELAX-NEXT: 0x20 R_LARCH_SUB8 .L3 0x0
3950
# RELAX-NEXT: 0x21 R_LARCH_ADD16 .L4 0x0
@@ -57,7 +68,7 @@
5768

5869
# RELAX: Hex dump of section '.data':
5970
# RELAX-NEXT: 0x00000000 04040004 00000004 00000000 00000004
60-
# RELAX-NEXT: 0x00000010 0c0c000c 0000000c 00000000 0000000c
71+
# RELAX-NEXT: 0x00000010 00000000 00000000 00000000 00000000
6172
# RELAX-NEXT: 0x00000020 00000000 00000000 00000000 00000000
6273
# RELAX-NEXT: 0x00000030 00000000 00000000 00000000 000000
6374

@@ -78,7 +89,7 @@
7889
.word .L2 - .L1
7990
.dword .L2 - .L1
8091
.uleb128 .L2 - .L1
81-
## TODO Handle alignment directive.
92+
## With relaxation, emit relocs because the .align makes the diff variable.
8293
.byte .L3 - .L2
8394
.short .L3 - .L2
8495
.word .L3 - .L2
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
## The file testing Nop insertion with R_LARCH_ALIGN for relaxation.
2+
3+
# RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=-relax %s -o %t
4+
# RUN: llvm-objdump -d %t | FileCheck %s --check-prefix=INSTR
5+
# RUN: llvm-readobj -r %t | FileCheck %s --check-prefix=RELOC
6+
# RUN: llvm-mc --filetype=obj --triple=loongarch64 --mattr=+relax %s -o %t.r
7+
# RUN: llvm-objdump -d %t.r | FileCheck %s --check-prefixes=INSTR,RELAX-INSTR
8+
# RUN: llvm-readobj -r %t.r | FileCheck %s --check-prefixes=RELOC,RELAX-RELOC
9+
10+
.text
11+
break 0
12+
# INSTR: break 0
13+
14+
## Not emit R_LARCH_ALIGN if alignment directive is less than or equal to
15+
## minimum code alignment(a.k.a 4).
16+
.p2align 2
17+
.p2align 1
18+
.p2align 0
19+
20+
## Not emit instructions if max emit bytes less than min nop size.
21+
.p2align 4, , 2
22+
23+
## Not emit R_LARCH_ALIGN if alignment directive with specific padding value.
24+
## The behavior is the same as GNU assembler.
25+
break 1
26+
.p2align 4, 1
27+
# INSTR-NEXT: break 1
28+
# INSTR-COUNT-2: 01 01 01 01
29+
30+
break 2
31+
.p2align 4, 1, 12
32+
# INSTR-NEXT: break 2
33+
# INSTR-COUNT-3: 01 01 01 01
34+
35+
break 3
36+
.p2align 4
37+
# INSTR-NEXT: break 3
38+
# INSTR-COUNT-3: nop
39+
40+
break 4
41+
.p2align 5
42+
.p2align 4
43+
# INSTR-NEXT: break 4
44+
# INSTR-COUNT-3: nop
45+
# RELAX-INSTR-COUNT-7: nop
46+
47+
break 5
48+
.p2align 4, , 11
49+
# INSTR-NEXT: break 5
50+
# RELAX-INSTR-COUNT-3: nop
51+
52+
break 6
53+
## Not emit the third parameter.
54+
.p2align 4, , 12
55+
# INSTR-NEXT: break 6
56+
# INSTR-NEXT: nop
57+
# INSTR-NEXT: nop
58+
# RELAX-INSTR-NEXT: nop
59+
60+
ret
61+
# INSNR-NEXT: ret
62+
63+
## Test the symbol index is different from .text.
64+
.section .text2, "ax"
65+
.p2align 4
66+
break 7
67+
68+
# RELOC: Relocations [
69+
# RELAX-RELOC-NEXT: Section ({{.*}}) .rela.text {
70+
# RELAX-RELOC-NEXT: 0x24 R_LARCH_ALIGN .Lla-relax-align0 0x4
71+
# RELAX-RELOC-NEXT: 0x34 R_LARCH_ALIGN .Lla-relax-align0 0x5
72+
# RELAX-RELOC-NEXT: 0x50 R_LARCH_ALIGN .Lla-relax-align0 0x4
73+
# RELAX-RELOC-NEXT: 0x60 R_LARCH_ALIGN .Lla-relax-align0 0xB04
74+
# RELAX-RELOC-NEXT: 0x70 R_LARCH_ALIGN .Lla-relax-align0 0x4
75+
# RELAX-RELOC-NEXT: }
76+
# RELAX-RELOC-NEXT: Section ({{.*}}) .rela.text2 {
77+
# RELAX-RELOC-NEXT: 0x0 R_LARCH_ALIGN .Lla-relax-align1 0x4
78+
# RELAX-RELOC-NEXT: }
79+
# RELOC-NEXT: ]

0 commit comments

Comments
 (0)