/src/llvm-project/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===-- SystemZMCAsmBackend.cpp - SystemZ assembler backend ---------------===// |
2 | | // |
3 | | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | | // See https://llvm.org/LICENSE.txt for license information. |
5 | | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | | // |
7 | | //===----------------------------------------------------------------------===// |
8 | | |
9 | | #include "MCTargetDesc/SystemZMCFixups.h" |
10 | | #include "MCTargetDesc/SystemZMCTargetDesc.h" |
11 | | #include "llvm/ADT/StringSwitch.h" |
12 | | #include "llvm/MC/MCAsmBackend.h" |
13 | | #include "llvm/MC/MCAssembler.h" |
14 | | #include "llvm/MC/MCContext.h" |
15 | | #include "llvm/MC/MCELFObjectWriter.h" |
16 | | #include "llvm/MC/MCFixupKindInfo.h" |
17 | | #include "llvm/MC/MCInst.h" |
18 | | #include "llvm/MC/MCObjectWriter.h" |
19 | | #include "llvm/MC/MCSubtargetInfo.h" |
20 | | |
21 | | using namespace llvm; |
22 | | |
23 | | // Value is a fully-resolved relocation value: Symbol + Addend [- Pivot]. |
24 | | // Return the bits that should be installed in a relocation field for |
25 | | // fixup kind Kind. |
26 | | static uint64_t extractBitsForFixup(MCFixupKind Kind, uint64_t Value, |
27 | 0 | const MCFixup &Fixup, MCContext &Ctx) { |
28 | 0 | if (Kind < FirstTargetFixupKind) |
29 | 0 | return Value; |
30 | | |
31 | 0 | auto checkFixupInRange = [&](int64_t Min, int64_t Max) -> bool { |
32 | 0 | int64_t SVal = int64_t(Value); |
33 | 0 | if (SVal < Min || SVal > Max) { |
34 | 0 | Ctx.reportError(Fixup.getLoc(), "operand out of range (" + Twine(SVal) + |
35 | 0 | " not between " + Twine(Min) + |
36 | 0 | " and " + Twine(Max) + ")"); |
37 | 0 | return false; |
38 | 0 | } |
39 | 0 | return true; |
40 | 0 | }; |
41 | |
|
42 | 0 | auto handlePCRelFixupValue = [&](unsigned W) -> uint64_t { |
43 | 0 | if (Value % 2 != 0) |
44 | 0 | Ctx.reportError(Fixup.getLoc(), "Non-even PC relative offset."); |
45 | 0 | if (!checkFixupInRange(minIntN(W) * 2, maxIntN(W) * 2)) |
46 | 0 | return 0; |
47 | 0 | return (int64_t)Value / 2; |
48 | 0 | }; |
49 | |
|
50 | 0 | auto handleImmValue = [&](bool IsSigned, unsigned W) -> uint64_t { |
51 | 0 | if (!(IsSigned ? checkFixupInRange(minIntN(W), maxIntN(W)) |
52 | 0 | : checkFixupInRange(0, maxUIntN(W)))) |
53 | 0 | return 0; |
54 | 0 | return Value; |
55 | 0 | }; |
56 | |
|
57 | 0 | switch (unsigned(Kind)) { |
58 | 0 | case SystemZ::FK_390_PC12DBL: |
59 | 0 | return handlePCRelFixupValue(12); |
60 | 0 | case SystemZ::FK_390_PC16DBL: |
61 | 0 | return handlePCRelFixupValue(16); |
62 | 0 | case SystemZ::FK_390_PC24DBL: |
63 | 0 | return handlePCRelFixupValue(24); |
64 | 0 | case SystemZ::FK_390_PC32DBL: |
65 | 0 | return handlePCRelFixupValue(32); |
66 | | |
67 | 0 | case SystemZ::FK_390_TLS_CALL: |
68 | 0 | return 0; |
69 | | |
70 | 0 | case SystemZ::FK_390_S8Imm: |
71 | 0 | return handleImmValue(true, 8); |
72 | 0 | case SystemZ::FK_390_S16Imm: |
73 | 0 | return handleImmValue(true, 16); |
74 | 0 | case SystemZ::FK_390_S20Imm: { |
75 | 0 | Value = handleImmValue(true, 20); |
76 | | // S20Imm is used only for signed 20-bit displacements. |
77 | | // The high byte of a 20 bit displacement value comes first. |
78 | 0 | uint64_t DLo = Value & 0xfff; |
79 | 0 | uint64_t DHi = (Value >> 12) & 0xff; |
80 | 0 | return (DLo << 8) | DHi; |
81 | 0 | } |
82 | 0 | case SystemZ::FK_390_S32Imm: |
83 | 0 | return handleImmValue(true, 32); |
84 | 0 | case SystemZ::FK_390_U1Imm: |
85 | 0 | return handleImmValue(false, 1); |
86 | 0 | case SystemZ::FK_390_U2Imm: |
87 | 0 | return handleImmValue(false, 2); |
88 | 0 | case SystemZ::FK_390_U3Imm: |
89 | 0 | return handleImmValue(false, 3); |
90 | 0 | case SystemZ::FK_390_U4Imm: |
91 | 0 | return handleImmValue(false, 4); |
92 | 0 | case SystemZ::FK_390_U8Imm: |
93 | 0 | return handleImmValue(false, 8); |
94 | 0 | case SystemZ::FK_390_U12Imm: |
95 | 0 | return handleImmValue(false, 12); |
96 | 0 | case SystemZ::FK_390_U16Imm: |
97 | 0 | return handleImmValue(false, 16); |
98 | 0 | case SystemZ::FK_390_U32Imm: |
99 | 0 | return handleImmValue(false, 32); |
100 | 0 | case SystemZ::FK_390_U48Imm: |
101 | 0 | return handleImmValue(false, 48); |
102 | 0 | } |
103 | | |
104 | 0 | llvm_unreachable("Unknown fixup kind!"); |
105 | 0 | } |
106 | | |
107 | | namespace { |
108 | | class SystemZMCAsmBackend : public MCAsmBackend { |
109 | | public: |
110 | 0 | SystemZMCAsmBackend() : MCAsmBackend(llvm::endianness::big) {} |
111 | | |
112 | | // Override MCAsmBackend |
113 | 0 | unsigned getNumFixupKinds() const override { |
114 | 0 | return SystemZ::NumTargetFixupKinds; |
115 | 0 | } |
116 | | std::optional<MCFixupKind> getFixupKind(StringRef Name) const override; |
117 | | const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override; |
118 | | bool shouldForceRelocation(const MCAssembler &Asm, const MCFixup &Fixup, |
119 | | const MCValue &Target, |
120 | | const MCSubtargetInfo *STI) override; |
121 | | void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, |
122 | | const MCValue &Target, MutableArrayRef<char> Data, |
123 | | uint64_t Value, bool IsResolved, |
124 | | const MCSubtargetInfo *STI) const override; |
125 | | bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value, |
126 | | const MCRelaxableFragment *Fragment, |
127 | 0 | const MCAsmLayout &Layout) const override { |
128 | 0 | return false; |
129 | 0 | } |
130 | | bool writeNopData(raw_ostream &OS, uint64_t Count, |
131 | | const MCSubtargetInfo *STI) const override; |
132 | | }; |
133 | | } // end anonymous namespace |
134 | | |
135 | | std::optional<MCFixupKind> |
136 | 0 | SystemZMCAsmBackend::getFixupKind(StringRef Name) const { |
137 | 0 | unsigned Type = llvm::StringSwitch<unsigned>(Name) |
138 | 0 | #define ELF_RELOC(X, Y) .Case(#X, Y) |
139 | 0 | #include "llvm/BinaryFormat/ELFRelocs/SystemZ.def" |
140 | 0 | #undef ELF_RELOC |
141 | 0 | .Case("BFD_RELOC_NONE", ELF::R_390_NONE) |
142 | 0 | .Case("BFD_RELOC_8", ELF::R_390_8) |
143 | 0 | .Case("BFD_RELOC_16", ELF::R_390_16) |
144 | 0 | .Case("BFD_RELOC_32", ELF::R_390_32) |
145 | 0 | .Case("BFD_RELOC_64", ELF::R_390_64) |
146 | 0 | .Default(-1u); |
147 | 0 | if (Type != -1u) |
148 | 0 | return static_cast<MCFixupKind>(FirstLiteralRelocationKind + Type); |
149 | 0 | return std::nullopt; |
150 | 0 | } |
151 | | |
152 | | const MCFixupKindInfo & |
153 | 0 | SystemZMCAsmBackend::getFixupKindInfo(MCFixupKind Kind) const { |
154 | | // Fixup kinds from .reloc directive are like R_390_NONE. They |
155 | | // do not require any extra processing. |
156 | 0 | if (Kind >= FirstLiteralRelocationKind) |
157 | 0 | return MCAsmBackend::getFixupKindInfo(FK_NONE); |
158 | | |
159 | 0 | if (Kind < FirstTargetFixupKind) |
160 | 0 | return MCAsmBackend::getFixupKindInfo(Kind); |
161 | | |
162 | 0 | assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() && |
163 | 0 | "Invalid kind!"); |
164 | 0 | return SystemZ::MCFixupKindInfos[Kind - FirstTargetFixupKind]; |
165 | 0 | } |
166 | | |
167 | | bool SystemZMCAsmBackend::shouldForceRelocation(const MCAssembler &, |
168 | | const MCFixup &Fixup, |
169 | | const MCValue &, |
170 | 0 | const MCSubtargetInfo *STI) { |
171 | 0 | return Fixup.getKind() >= FirstLiteralRelocationKind; |
172 | 0 | } |
173 | | |
174 | | void SystemZMCAsmBackend::applyFixup(const MCAssembler &Asm, |
175 | | const MCFixup &Fixup, |
176 | | const MCValue &Target, |
177 | | MutableArrayRef<char> Data, uint64_t Value, |
178 | | bool IsResolved, |
179 | 0 | const MCSubtargetInfo *STI) const { |
180 | 0 | MCFixupKind Kind = Fixup.getKind(); |
181 | 0 | if (Kind >= FirstLiteralRelocationKind) |
182 | 0 | return; |
183 | 0 | unsigned Offset = Fixup.getOffset(); |
184 | 0 | unsigned BitSize = getFixupKindInfo(Kind).TargetSize; |
185 | 0 | unsigned Size = (BitSize + 7) / 8; |
186 | |
|
187 | 0 | assert(Offset + Size <= Data.size() && "Invalid fixup offset!"); |
188 | | |
189 | | // Big-endian insertion of Size bytes. |
190 | 0 | Value = extractBitsForFixup(Kind, Value, Fixup, Asm.getContext()); |
191 | 0 | if (BitSize < 64) |
192 | 0 | Value &= ((uint64_t)1 << BitSize) - 1; |
193 | 0 | unsigned ShiftValue = (Size * 8) - 8; |
194 | 0 | for (unsigned I = 0; I != Size; ++I) { |
195 | 0 | Data[Offset + I] |= uint8_t(Value >> ShiftValue); |
196 | 0 | ShiftValue -= 8; |
197 | 0 | } |
198 | 0 | } |
199 | | |
200 | | bool SystemZMCAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count, |
201 | 0 | const MCSubtargetInfo *STI) const { |
202 | 0 | for (uint64_t I = 0; I != Count; ++I) |
203 | 0 | OS << '\x7'; |
204 | 0 | return true; |
205 | 0 | } |
206 | | |
207 | | namespace { |
208 | | class ELFSystemZAsmBackend : public SystemZMCAsmBackend { |
209 | | uint8_t OSABI; |
210 | | |
211 | | public: |
212 | 0 | ELFSystemZAsmBackend(uint8_t OsABI) : SystemZMCAsmBackend(), OSABI(OsABI){}; |
213 | | |
214 | | std::unique_ptr<MCObjectTargetWriter> |
215 | 0 | createObjectTargetWriter() const override { |
216 | 0 | return createSystemZELFObjectWriter(OSABI); |
217 | 0 | } |
218 | | }; |
219 | | |
220 | | class GOFFSystemZAsmBackend : public SystemZMCAsmBackend { |
221 | | public: |
222 | 0 | GOFFSystemZAsmBackend() : SystemZMCAsmBackend(){}; |
223 | | |
224 | | std::unique_ptr<MCObjectTargetWriter> |
225 | 0 | createObjectTargetWriter() const override { |
226 | 0 | return createSystemZGOFFObjectWriter(); |
227 | 0 | } |
228 | | }; |
229 | | } // namespace |
230 | | |
231 | | MCAsmBackend *llvm::createSystemZMCAsmBackend(const Target &T, |
232 | | const MCSubtargetInfo &STI, |
233 | | const MCRegisterInfo &MRI, |
234 | 0 | const MCTargetOptions &Options) { |
235 | 0 | if (STI.getTargetTriple().isOSzOS()) { |
236 | 0 | return new GOFFSystemZAsmBackend(); |
237 | 0 | } |
238 | | |
239 | 0 | uint8_t OSABI = |
240 | 0 | MCELFObjectTargetWriter::getOSABI(STI.getTargetTriple().getOS()); |
241 | 0 | return new ELFSystemZAsmBackend(OSABI); |
242 | 0 | } |