1 //===-- CSKYAsmBackend.cpp - CSKY Assembler Backend -----------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "CSKYAsmBackend.h"
10 #include "MCTargetDesc/CSKYMCTargetDesc.h"
11 #include "llvm/ADT/DenseMap.h"
12 #include "llvm/MC/MCAssembler.h"
13 #include "llvm/MC/MCContext.h"
14 #include "llvm/MC/MCFixupKindInfo.h"
15 #include "llvm/MC/MCObjectWriter.h"
16 #include "llvm/Support/Debug.h"
18 #define DEBUG_TYPE "csky-asmbackend"
22 std::unique_ptr
<MCObjectTargetWriter
>
23 CSKYAsmBackend::createObjectTargetWriter() const {
24 return createCSKYELFObjectWriter();
27 const MCFixupKindInfo
&
28 CSKYAsmBackend::getFixupKindInfo(MCFixupKind Kind
) const {
30 static llvm::DenseMap
<unsigned, MCFixupKindInfo
> Infos
= {
31 {CSKY::Fixups::fixup_csky_addr32
, {"fixup_csky_addr32", 0, 32, 0}},
32 {CSKY::Fixups::fixup_csky_addr_hi16
, {"fixup_csky_addr_hi16", 0, 32, 0}},
33 {CSKY::Fixups::fixup_csky_addr_lo16
, {"fixup_csky_addr_lo16", 0, 32, 0}},
34 {CSKY::Fixups::fixup_csky_pcrel_imm16_scale2
,
35 {"fixup_csky_pcrel_imm16_scale2", 0, 32, MCFixupKindInfo::FKF_IsPCRel
}},
36 {CSKY::Fixups::fixup_csky_pcrel_uimm16_scale4
,
37 {"fixup_csky_pcrel_uimm16_scale4", 0, 32,
38 MCFixupKindInfo::FKF_IsPCRel
|
39 MCFixupKindInfo::FKF_IsAlignedDownTo32Bits
}},
40 {CSKY::Fixups::fixup_csky_pcrel_uimm8_scale4
,
41 {"fixup_csky_pcrel_uimm8_scale4", 0, 32,
42 MCFixupKindInfo::FKF_IsPCRel
|
43 MCFixupKindInfo::FKF_IsAlignedDownTo32Bits
}},
44 {CSKY::Fixups::fixup_csky_pcrel_imm26_scale2
,
45 {"fixup_csky_pcrel_imm26_scale2", 0, 32, MCFixupKindInfo::FKF_IsPCRel
}},
46 {CSKY::Fixups::fixup_csky_pcrel_imm18_scale2
,
47 {"fixup_csky_pcrel_imm18_scale2", 0, 32, MCFixupKindInfo::FKF_IsPCRel
}},
48 {CSKY::Fixups::fixup_csky_got32
, {"fixup_csky_got32", 0, 32, 0}},
49 {CSKY::Fixups::fixup_csky_got_imm18_scale4
,
50 {"fixup_csky_got_imm18_scale4", 0, 32, 0}},
51 {CSKY::Fixups::fixup_csky_gotoff
, {"fixup_csky_gotoff", 0, 32, 0}},
52 {CSKY::Fixups::fixup_csky_gotpc
,
53 {"fixup_csky_gotpc", 0, 32, MCFixupKindInfo::FKF_IsPCRel
}},
54 {CSKY::Fixups::fixup_csky_plt32
, {"fixup_csky_plt32", 0, 32, 0}},
55 {CSKY::Fixups::fixup_csky_plt_imm18_scale4
,
56 {"fixup_csky_plt_imm18_scale4", 0, 32, 0}},
57 {CSKY::Fixups::fixup_csky_pcrel_imm10_scale2
,
58 {"fixup_csky_pcrel_imm10_scale2", 0, 16, MCFixupKindInfo::FKF_IsPCRel
}},
59 {CSKY::Fixups::fixup_csky_pcrel_uimm7_scale4
,
60 {"fixup_csky_pcrel_uimm7_scale4", 0, 16,
61 MCFixupKindInfo::FKF_IsPCRel
|
62 MCFixupKindInfo::FKF_IsAlignedDownTo32Bits
}},
63 {CSKY::Fixups::fixup_csky_doffset_imm18
,
64 {"fixup_csky_doffset_imm18", 0, 18, 0}},
65 {CSKY::Fixups::fixup_csky_doffset_imm18_scale2
,
66 {"fixup_csky_doffset_imm18_scale2", 0, 18, 0}},
67 {CSKY::Fixups::fixup_csky_doffset_imm18_scale4
,
68 {"fixup_csky_doffset_imm18_scale4", 0, 18, 0}}};
70 assert(Infos
.size() == CSKY::NumTargetFixupKinds
&&
71 "Not all fixup kinds added to Infos array");
73 if (FirstTargetFixupKind
<= Kind
&& Kind
< FirstLiteralRelocationKind
) {
74 assert(unsigned(Kind
- FirstTargetFixupKind
) < getNumFixupKinds() &&
78 } else if (Kind
< FirstTargetFixupKind
) {
79 return MCAsmBackend::getFixupKindInfo(Kind
);
81 return MCAsmBackend::getFixupKindInfo(FK_NONE
);
85 static uint64_t adjustFixupValue(const MCFixup
&Fixup
, uint64_t Value
,
87 switch (Fixup
.getTargetKind()) {
89 llvm_unreachable("Unknown fixup kind!");
90 case CSKY::fixup_csky_got32
:
91 case CSKY::fixup_csky_got_imm18_scale4
:
92 case CSKY::fixup_csky_gotoff
:
93 case CSKY::fixup_csky_gotpc
:
94 case CSKY::fixup_csky_plt32
:
95 case CSKY::fixup_csky_plt_imm18_scale4
:
96 llvm_unreachable("Relocation should be unconditionally forced\n");
102 case CSKY::fixup_csky_addr32
:
103 return Value
& 0xffffffff;
104 case CSKY::fixup_csky_pcrel_imm16_scale2
:
105 if (!isIntN(17, Value
))
106 Ctx
.reportError(Fixup
.getLoc(), "out of range pc-relative fixup value.");
108 Ctx
.reportError(Fixup
.getLoc(), "fixup value must be 2-byte aligned.");
110 return (Value
>> 1) & 0xffff;
111 case CSKY::fixup_csky_pcrel_uimm16_scale4
:
112 if (!isUIntN(18, Value
))
113 Ctx
.reportError(Fixup
.getLoc(), "out of range pc-relative fixup value.");
115 Ctx
.reportError(Fixup
.getLoc(), "fixup value must be 4-byte aligned.");
117 return (Value
>> 2) & 0xffff;
118 case CSKY::fixup_csky_pcrel_imm26_scale2
:
119 if (!isIntN(27, Value
))
120 Ctx
.reportError(Fixup
.getLoc(), "out of range pc-relative fixup value.");
122 Ctx
.reportError(Fixup
.getLoc(), "fixup value must be 2-byte aligned.");
124 return (Value
>> 1) & 0x3ffffff;
125 case CSKY::fixup_csky_pcrel_imm18_scale2
:
126 if (!isIntN(19, Value
))
127 Ctx
.reportError(Fixup
.getLoc(), "out of range pc-relative fixup value.");
129 Ctx
.reportError(Fixup
.getLoc(), "fixup value must be 2-byte aligned.");
131 return (Value
>> 1) & 0x3ffff;
132 case CSKY::fixup_csky_pcrel_uimm8_scale4
: {
133 if (!isUIntN(10, Value
))
134 Ctx
.reportError(Fixup
.getLoc(), "out of range pc-relative fixup value.");
136 Ctx
.reportError(Fixup
.getLoc(), "fixup value must be 4-byte aligned.");
138 unsigned IMM4L
= (Value
>> 2) & 0xf;
139 unsigned IMM4H
= (Value
>> 6) & 0xf;
141 Value
= (IMM4H
<< 21) | (IMM4L
<< 4);
144 case CSKY::fixup_csky_pcrel_imm10_scale2
:
145 if (!isIntN(11, Value
))
146 Ctx
.reportError(Fixup
.getLoc(), "out of range pc-relative fixup value.");
148 Ctx
.reportError(Fixup
.getLoc(), "fixup value must be 2-byte aligned.");
150 return (Value
>> 1) & 0x3ff;
151 case CSKY::fixup_csky_pcrel_uimm7_scale4
:
152 if ((Value
>> 2) > 0xfe)
153 Ctx
.reportError(Fixup
.getLoc(), "out of range pc-relative fixup value.");
155 Ctx
.reportError(Fixup
.getLoc(), "fixup value must be 4-byte aligned.");
157 if ((Value
>> 2) <= 0x7f) {
158 unsigned IMM5L
= (Value
>> 2) & 0x1f;
159 unsigned IMM2H
= (Value
>> 7) & 0x3;
161 Value
= (1 << 12) | (IMM2H
<< 8) | IMM5L
;
163 unsigned IMM5L
= (~Value
>> 2) & 0x1f;
164 unsigned IMM2H
= (~Value
>> 7) & 0x3;
166 Value
= (IMM2H
<< 8) | IMM5L
;
173 bool CSKYAsmBackend::fixupNeedsRelaxationAdvanced(const MCAssembler
&Asm
,
174 const MCFixup
&Fixup
,
175 bool Resolved
, uint64_t Value
,
176 const MCRelaxableFragment
*DF
,
177 const bool WasForced
) const {
178 // Return true if the symbol is actually unresolved.
179 // Resolved could be always false when shouldForceRelocation return true.
180 // We use !WasForced to indicate that the symbol is unresolved and not forced
181 // by shouldForceRelocation.
182 if (!Resolved
&& !WasForced
)
185 int64_t Offset
= int64_t(Value
);
186 switch (Fixup
.getTargetKind()) {
189 case CSKY::fixup_csky_pcrel_imm10_scale2
:
190 return !isShiftedInt
<10, 1>(Offset
);
191 case CSKY::fixup_csky_pcrel_imm16_scale2
:
192 return !isShiftedInt
<16, 1>(Offset
);
193 case CSKY::fixup_csky_pcrel_imm26_scale2
:
194 return !isShiftedInt
<26, 1>(Offset
);
195 case CSKY::fixup_csky_pcrel_uimm7_scale4
:
196 return ((Value
>> 2) > 0xfe) || (Value
& 0x3);
200 void CSKYAsmBackend::applyFixup(const MCAssembler
&Asm
, const MCFixup
&Fixup
,
201 const MCValue
&Target
,
202 MutableArrayRef
<char> Data
, uint64_t Value
,
204 const MCSubtargetInfo
*STI
) const {
205 MCFixupKind Kind
= Fixup
.getKind();
206 if (Kind
>= FirstLiteralRelocationKind
)
208 MCContext
&Ctx
= Asm
.getContext();
209 MCFixupKindInfo Info
= getFixupKindInfo(Kind
);
211 return; // Doesn't change encoding.
212 // Apply any target-specific value adjustments.
213 Value
= adjustFixupValue(Fixup
, Value
, Ctx
);
215 // Shift the value into position.
216 Value
<<= Info
.TargetOffset
;
218 unsigned Offset
= Fixup
.getOffset();
219 unsigned NumBytes
= alignTo(Info
.TargetSize
+ Info
.TargetOffset
, 8) / 8;
221 assert(Offset
+ NumBytes
<= Data
.size() && "Invalid fixup offset!");
223 // For each byte of the fragment that the fixup touches, mask in the
224 // bits from the fixup value.
225 bool IsLittleEndian
= (Endian
== llvm::endianness::little
);
226 bool IsInstFixup
= (Kind
>= FirstTargetFixupKind
);
228 if (IsLittleEndian
&& IsInstFixup
&& (NumBytes
== 4)) {
229 Data
[Offset
+ 0] |= uint8_t((Value
>> 16) & 0xff);
230 Data
[Offset
+ 1] |= uint8_t((Value
>> 24) & 0xff);
231 Data
[Offset
+ 2] |= uint8_t(Value
& 0xff);
232 Data
[Offset
+ 3] |= uint8_t((Value
>> 8) & 0xff);
234 for (unsigned I
= 0; I
!= NumBytes
; I
++) {
235 unsigned Idx
= IsLittleEndian
? I
: (NumBytes
- 1 - I
);
236 Data
[Offset
+ Idx
] |= uint8_t((Value
>> (I
* 8)) & 0xff);
241 bool CSKYAsmBackend::mayNeedRelaxation(const MCInst
&Inst
,
242 const MCSubtargetInfo
&STI
) const {
243 switch (Inst
.getOpcode()) {
250 if (!STI
.hasFeature(CSKY::Has2E3
))
262 bool CSKYAsmBackend::shouldForceRelocation(const MCAssembler
&Asm
,
263 const MCFixup
&Fixup
,
264 const MCValue
&Target
,
265 const uint64_t /*Value*/,
266 const MCSubtargetInfo
* /*STI*/) {
267 if (Fixup
.getKind() >= FirstLiteralRelocationKind
)
269 switch (Fixup
.getTargetKind()) {
272 case CSKY::fixup_csky_got32
:
273 case CSKY::fixup_csky_got_imm18_scale4
:
274 case CSKY::fixup_csky_gotoff
:
275 case CSKY::fixup_csky_gotpc
:
276 case CSKY::fixup_csky_plt32
:
277 case CSKY::fixup_csky_plt_imm18_scale4
:
278 case CSKY::fixup_csky_doffset_imm18
:
279 case CSKY::fixup_csky_doffset_imm18_scale2
:
280 case CSKY::fixup_csky_doffset_imm18_scale4
:
287 bool CSKYAsmBackend::fixupNeedsRelaxation(const MCFixup
&Fixup
,
288 uint64_t Value
) const {
292 void CSKYAsmBackend::relaxInstruction(MCInst
&Inst
,
293 const MCSubtargetInfo
&STI
) const {
296 switch (Inst
.getOpcode()) {
298 LLVM_DEBUG(Inst
.dump());
299 llvm_unreachable("Opcode not expected!");
301 Res
.setOpcode(CSKY::LRW32
);
302 Res
.addOperand(Inst
.getOperand(0));
303 Res
.addOperand(Inst
.getOperand(1));
306 Res
.setOpcode(CSKY::BR32
);
307 Res
.addOperand(Inst
.getOperand(0));
310 Res
.setOpcode(CSKY::JSRI32
);
311 Res
.addOperand(Inst
.getOperand(1));
314 Res
.setOpcode(CSKY::JMPI32
);
315 Res
.addOperand(Inst
.getOperand(1));
319 Res
.setOpcode(Inst
.getOpcode() == CSKY::JBT32
? CSKY::JBT_E
: CSKY::JBF_E
);
320 Res
.addOperand(Inst
.getOperand(0));
321 Res
.addOperand(Inst
.getOperand(1));
322 Res
.addOperand(Inst
.getOperand(2));
325 Res
.setOpcode(CSKY::JBR32
);
326 Res
.addOperand(Inst
.getOperand(0));
327 Res
.addOperand(Inst
.getOperand(1));
333 if (STI
.hasFeature(CSKY::HasE2
))
334 opcode
= Inst
.getOpcode() == CSKY::JBT16
? CSKY::JBT32
: CSKY::JBF32
;
336 opcode
= Inst
.getOpcode() == CSKY::JBT16
? CSKY::JBT_E
: CSKY::JBF_E
;
338 Res
.setOpcode(opcode
);
339 Res
.addOperand(Inst
.getOperand(0));
340 Res
.addOperand(Inst
.getOperand(1));
341 Res
.addOperand(Inst
.getOperand(2));
344 Inst
= std::move(Res
);
347 bool CSKYAsmBackend::writeNopData(raw_ostream
&OS
, uint64_t Count
,
348 const MCSubtargetInfo
*STI
) const {
349 OS
.write_zeros(Count
);
353 MCAsmBackend
*llvm::createCSKYAsmBackend(const Target
&T
,
354 const MCSubtargetInfo
&STI
,
355 const MCRegisterInfo
&MRI
,
356 const MCTargetOptions
&Options
) {
357 return new CSKYAsmBackend(STI
, Options
);