Skip to content

Commit 2ccb941

Browse files
committed
[AVR] Fix global references to function symbols
References to functions are in program memory and need a `pm()` fixup. This should fix trait objects for Rust on AVR. Differential Revision: https://reviews.llvm.org/D87631 Patch by Alex Mikhalev.
1 parent a50ab86 commit 2ccb941

File tree

8 files changed

+146
-3
lines changed

8 files changed

+146
-3
lines changed

llvm/include/llvm/MC/MCExpr.h

+1
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,7 @@ class MCSymbolRefExpr : public MCExpr {
242242
VK_AVR_DIFF8,
243243
VK_AVR_DIFF16,
244244
VK_AVR_DIFF32,
245+
VK_AVR_PM,
245246

246247
VK_PPC_LO, // symbol@l
247248
VK_PPC_HI, // symbol@h

llvm/lib/MC/MCExpr.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,7 @@ StringRef MCSymbolRefExpr::getVariantKindName(VariantKind Kind) {
269269
case VK_AVR_DIFF8: return "diff8";
270270
case VK_AVR_DIFF16: return "diff16";
271271
case VK_AVR_DIFF32: return "diff32";
272+
case VK_AVR_PM: return "pm";
272273
case VK_PPC_LO: return "l";
273274
case VK_PPC_HI: return "h";
274275
case VK_PPC_HA: return "ha";

llvm/lib/Target/AVR/AVRAsmPrinter.cpp

+17
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "AVRMCInstLower.h"
1616
#include "AVRSubtarget.h"
1717
#include "MCTargetDesc/AVRInstPrinter.h"
18+
#include "MCTargetDesc/AVRMCExpr.h"
1819
#include "TargetInfo/AVRTargetInfo.h"
1920

2021
#include "llvm/CodeGen/AsmPrinter.h"
@@ -53,6 +54,8 @@ class AVRAsmPrinter : public AsmPrinter {
5354

5455
void emitInstruction(const MachineInstr *MI) override;
5556

57+
const MCExpr *lowerConstant(const Constant *CV) override;
58+
5659
private:
5760
const MCRegisterInfo &MRI;
5861
};
@@ -176,6 +179,20 @@ void AVRAsmPrinter::emitInstruction(const MachineInstr *MI) {
176179
EmitToStreamer(*OutStreamer, I);
177180
}
178181

182+
const MCExpr *AVRAsmPrinter::lowerConstant(const Constant *CV) {
183+
MCContext &Ctx = OutContext;
184+
185+
if (const GlobalValue *GV = dyn_cast<GlobalValue>(CV)) {
186+
bool IsProgMem = GV->getAddressSpace() == AVR::ProgramMemory;
187+
if (IsProgMem) {
188+
const MCExpr *Expr = MCSymbolRefExpr::create(getSymbol(GV), Ctx);
189+
return AVRMCExpr::create(AVRMCExpr::VK_AVR_PM, Expr, false, Ctx);
190+
}
191+
}
192+
193+
return AsmPrinter::lowerConstant(CV);
194+
}
195+
179196
} // end of namespace llvm
180197

181198
extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeAVRAsmPrinter() {

llvm/lib/Target/AVR/MCTargetDesc/AVRELFObjectWriter.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "MCTargetDesc/AVRFixupKinds.h"
10+
#include "MCTargetDesc/AVRMCExpr.h"
1011
#include "MCTargetDesc/AVRMCTargetDesc.h"
1112

1213
#include "llvm/MC/MCAssembler.h"
@@ -72,6 +73,7 @@ unsigned AVRELFObjectWriter::getRelocType(MCContext &Ctx,
7273
case MCSymbolRefExpr::VK_None:
7374
return ELF::R_AVR_16;
7475
case MCSymbolRefExpr::VK_AVR_NONE:
76+
case MCSymbolRefExpr::VK_AVR_PM:
7577
return ELF::R_AVR_16_PM;
7678
case MCSymbolRefExpr::VK_AVR_DIFF16:
7779
return ELF::R_AVR_DIFF16;

llvm/lib/Target/AVR/MCTargetDesc/AVRMCExpr.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ const struct ModifierEntry {
2626
{"hh8", AVRMCExpr::VK_AVR_HH8}, // synonym with hlo8
2727
{"hlo8", AVRMCExpr::VK_AVR_HH8}, {"hhi8", AVRMCExpr::VK_AVR_HHI8},
2828

29+
{"pm", AVRMCExpr::VK_AVR_PM},
2930
{"pm_lo8", AVRMCExpr::VK_AVR_PM_LO8}, {"pm_hi8", AVRMCExpr::VK_AVR_PM_HI8},
3031
{"pm_hh8", AVRMCExpr::VK_AVR_PM_HH8},
3132

@@ -87,6 +88,9 @@ bool AVRMCExpr::evaluateAsRelocatableImpl(MCValue &Result,
8788
MCSymbolRefExpr::VariantKind Modifier = Sym->getKind();
8889
if (Modifier != MCSymbolRefExpr::VK_None)
8990
return false;
91+
if (Kind == VK_AVR_PM) {
92+
Modifier = MCSymbolRefExpr::VK_AVR_PM;
93+
}
9094

9195
Sym = MCSymbolRefExpr::create(&Sym->getSymbol(), Modifier, Context);
9296
Result = MCValue::get(Sym, Value.getSymB(), Value.getConstant());
@@ -131,6 +135,7 @@ int64_t AVRMCExpr::evaluateAsInt64(int64_t Value) const {
131135
Value &= 0xff0000;
132136
Value >>= 16;
133137
break;
138+
case AVRMCExpr::VK_AVR_PM:
134139
case AVRMCExpr::VK_AVR_GS:
135140
Value >>= 1; // Program memory addresses must always be shifted by one.
136141
break;
@@ -167,6 +172,7 @@ AVR::Fixups AVRMCExpr::getFixupKind() const {
167172
case VK_AVR_PM_HH8:
168173
Kind = isNegated() ? AVR::fixup_hh8_ldi_pm_neg : AVR::fixup_hh8_ldi_pm;
169174
break;
175+
case VK_AVR_PM:
170176
case VK_AVR_GS:
171177
Kind = AVR::fixup_16_pm;
172178
break;

llvm/lib/Target/AVR/MCTargetDesc/AVRMCExpr.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,14 @@ class AVRMCExpr : public MCTargetExpr {
2020
public:
2121
/// Specifies the type of an expression.
2222
enum VariantKind {
23-
VK_AVR_None,
23+
VK_AVR_None = 0,
2424

2525
VK_AVR_HI8, ///< Corresponds to `hi8()`.
2626
VK_AVR_LO8, ///< Corresponds to `lo8()`.
2727
VK_AVR_HH8, ///< Corresponds to `hlo8() and hh8()`.
2828
VK_AVR_HHI8, ///< Corresponds to `hhi8()`.
2929

30+
VK_AVR_PM, ///< Corresponds to `pm()`, reference to program memory.
3031
VK_AVR_PM_LO8, ///< Corresponds to `pm_lo8()`.
3132
VK_AVR_PM_HI8, ///< Corresponds to `pm_hi8()`.
3233
VK_AVR_PM_HH8, ///< Corresponds to `pm_hh8()`.
+112
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
; RUN: llc < %s -march=avr -filetype=asm | FileCheck %s -check-prefix=CHECK-ASM
2+
; RUN: llc < %s -march=avr -filetype=obj | llvm-objdump -Dr - \
3+
; RUN: | FileCheck %s -check-prefix=CHECK-OBJ
4+
5+
; Somewhat pruned test case from rustc using trait objects
6+
7+
%TraitObjectA = type {}
8+
9+
; CHECK-ASM-LABEL: vtable.0:
10+
; CHECK-ASM-NEXT: .short pm(drop_in_place2)
11+
; CHECK-ASM-NEXT: .short 0
12+
; CHECK-ASM-NEXT: .short 1
13+
; CHECK-ASM-NEXT: .short pm(trait_fn2)
14+
15+
; CHECK-OBJ-LABEL: <vtable.0>:
16+
; CHECK-OBJ-NEXT: 00 00
17+
; CHECK-OBJ-NEXT: R_AVR_16_PM .text
18+
; CHECK-OBJ-NEXT: 00 00
19+
; CHECK-OBJ-NEXT: 01 00 00 00
20+
; CHECK-OBJ-NEXT: R_AVR_16_PM .text
21+
@vtable.0 = private constant {
22+
void (%TraitObjectA*) addrspace(1)*,
23+
i16,
24+
i16,
25+
i8 (%TraitObjectA*) addrspace(1)*
26+
} {
27+
void (%TraitObjectA*) addrspace(1)*
28+
@drop_in_place2,
29+
i16 0,
30+
i16 1,
31+
i8 (%TraitObjectA*) addrspace(1)*
32+
@trait_fn2
33+
}, align 1
34+
35+
; CHECK-ASM-LABEL: vtable.1:
36+
; CHECK-ASM-NEXT: .short pm(drop_in_place1)
37+
; CHECK-ASM-NEXT: .short 0
38+
; CHECK-ASM-NEXT: .short 1
39+
; CHECK-ASM-NEXT: .short pm(trait_fn1)
40+
41+
; CHECK-OBJ-LABEL: <vtable.1>:
42+
; CHECK-OBJ-NEXT: 00 00
43+
; CHECK-OBJ-NEXT: R_AVR_16_PM .text
44+
; CHECK-OBJ-NEXT: 00 00
45+
; CHECK-OBJ-NEXT: 01 00 00 00
46+
; CHECK-OBJ-NEXT: R_AVR_16_PM .text
47+
@vtable.1 = private constant {
48+
void (%TraitObjectA*) addrspace(1)*,
49+
i16,
50+
i16,
51+
i8 (%TraitObjectA*) addrspace(1)*
52+
} {
53+
void (%TraitObjectA*) addrspace(1)*
54+
@drop_in_place1,
55+
i16 0,
56+
i16 1,
57+
i8 (%TraitObjectA*) addrspace(1)*
58+
@trait_fn1
59+
}, align 1
60+
61+
define internal fastcc i8 @TraitObjectA_method(i1 zeroext %choice) addrspace(1) {
62+
start:
63+
%b = alloca %TraitObjectA, align 1
64+
65+
%c = select i1 %choice, [3 x i16]* bitcast ({
66+
void (%TraitObjectA*) addrspace(1)*,
67+
i16,
68+
i16,
69+
i8 (%TraitObjectA*) addrspace(1)*
70+
}* @vtable.0 to [3 x i16]*),
71+
[3 x i16]* bitcast ({
72+
void (%TraitObjectA*) addrspace(1)*,
73+
i16,
74+
i16,
75+
i8 (%TraitObjectA*) addrspace(1)*
76+
}* @vtable.1 to [3 x i16]*)
77+
%b2 = bitcast %TraitObjectA* %b to {}*
78+
79+
%res = call fastcc addrspace(1) i8 @call_trait_object({}* nonnull align 1 %b2, [3 x i16]* noalias readonly align 1 dereferenceable(6) %c)
80+
ret i8 %res
81+
}
82+
83+
define internal fastcc i8 @call_trait_object({}* nonnull align 1 %a, [3 x i16]* noalias nocapture readonly align 1 dereferenceable(6) %b) addrspace(1) {
84+
start:
85+
%b2 = getelementptr inbounds [3 x i16], [3 x i16]* %b, i16 0, i16 3
86+
%c = bitcast i16* %b2 to i8 ({}*) addrspace(1)**
87+
%d = load i8 ({}*) addrspace(1)*, i8 ({}*) addrspace(1)** %c, align 1, !invariant.load !1, !nonnull !1
88+
%res = tail call addrspace(1) i8 %d({}* nonnull align 1 %a)
89+
ret i8 %res
90+
}
91+
92+
define internal void @drop_in_place1(%TraitObjectA* nocapture %a) addrspace(1) {
93+
start:
94+
ret void
95+
}
96+
97+
define internal i8 @trait_fn1(%TraitObjectA* noalias nocapture nonnull readonly align 1 %self) addrspace(1) {
98+
start:
99+
ret i8 89
100+
}
101+
102+
define internal void @drop_in_place2(%TraitObjectA* nocapture %a) addrspace(1) {
103+
start:
104+
ret void
105+
}
106+
107+
define internal i8 @trait_fn2(%TraitObjectA* noalias nocapture nonnull readonly align 1 %self) addrspace(1) {
108+
start:
109+
ret i8 79
110+
}
111+
112+
!1 = !{}

llvm/test/MC/AVR/relocations.s

+5-2
Original file line numberDiff line numberDiff line change
@@ -135,12 +135,15 @@ ldi r17, lo8(gs(foo))
135135
; CHECK-NEXT: R_AVR_HI8_LDI_GS foo
136136
ldi r18, hi8(gs(foo))
137137

138-
; CHECK-NEXT: R_AVR_16
138+
; CHECK-NEXT: R_AVR_16 foo
139139
.short foo
140140

141-
; CHECK-NEXT: R_AVR_16_PM
141+
; CHECK-NEXT: R_AVR_16_PM foo
142142
.short gs(foo)
143143

144+
; CHECK-NEXT: R_AVR_16_PM foo
145+
.short pm(foo)
146+
144147
; CHECK-NEXT: R_AVR_8
145148
.byte foo
146149

0 commit comments

Comments
 (0)