1 //===-- CSKYAsmBackend.cpp - CSKY 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 "CSKYAsmBackend.h"
10 #include "MCTargetDesc/CSKYMCTargetDesc.h"
11 #include "llvm/ADT/DenseMap.h"
12 #include "llvm/MC/MCAsmLayout.h"
13 #include "llvm/MC/MCAssembler.h"
14 #include "llvm/MC/MCContext.h"
15 #include "llvm/MC/MCFixupKindInfo.h"
16 #include "llvm/MC/MCObjectWriter.h"
17 #include "llvm/Support/Debug.h"
18
19 #define DEBUG_TYPE "csky-asmbackend"
20
21 using namespace llvm;
22
23 std::unique_ptr<MCObjectTargetWriter>
createObjectTargetWriter() const24 CSKYAsmBackend::createObjectTargetWriter() const {
25 return createCSKYELFObjectWriter();
26 }
27
28 const MCFixupKindInfo &
getFixupKindInfo(MCFixupKind Kind) const29 CSKYAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {
30
31 static llvm::DenseMap<unsigned, MCFixupKindInfo> Infos = {
32 {CSKY::Fixups::fixup_csky_addr32, {"fixup_csky_addr32", 0, 32, 0}},
33 {CSKY::Fixups::fixup_csky_pcrel_imm16_scale2,
34 {"fixup_csky_pcrel_imm16_scale2", 0, 32, MCFixupKindInfo::FKF_IsPCRel}},
35 {CSKY::Fixups::fixup_csky_pcrel_uimm16_scale4,
36 {"fixup_csky_pcrel_uimm16_scale4", 0, 32, MCFixupKindInfo::FKF_IsPCRel}},
37 {CSKY::Fixups::fixup_csky_pcrel_imm26_scale2,
38 {"fixup_csky_pcrel_imm26_scale2", 0, 32, MCFixupKindInfo::FKF_IsPCRel}},
39 {CSKY::Fixups::fixup_csky_pcrel_imm18_scale2,
40 {"fixup_csky_pcrel_imm18_scale2", 0, 32, MCFixupKindInfo::FKF_IsPCRel}}};
41 assert(Infos.size() == CSKY::NumTargetFixupKinds &&
42 "Not all fixup kinds added to Infos array");
43
44 assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() &&
45 "Invalid kind!");
46 if (FirstTargetFixupKind <= Kind && Kind < FirstLiteralRelocationKind)
47 return Infos[Kind];
48 else if (Kind < FirstTargetFixupKind)
49 return MCAsmBackend::getFixupKindInfo(Kind);
50 else
51 return MCAsmBackend::getFixupKindInfo(FK_NONE);
52 }
53
adjustFixupValue(const MCFixup & Fixup,uint64_t Value,MCContext & Ctx)54 static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
55 MCContext &Ctx) {
56 switch (Fixup.getTargetKind()) {
57 default:
58 llvm_unreachable("Unknown fixup kind!");
59 case FK_Data_1:
60 case FK_Data_2:
61 case FK_Data_4:
62 case FK_Data_8:
63 return Value;
64 case CSKY::fixup_csky_addr32:
65 return Value & 0xffffffff;
66 case CSKY::fixup_csky_pcrel_imm16_scale2:
67 if (!isIntN(17, Value))
68 Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value.");
69 if (Value & 0x1)
70 Ctx.reportError(Fixup.getLoc(), "fixup value must be 2-byte aligned.");
71
72 return (Value >> 1) & 0xffff;
73 case CSKY::fixup_csky_pcrel_uimm16_scale4:
74 if (!isUIntN(18, Value))
75 Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value.");
76 if (Value & 0x3)
77 Ctx.reportError(Fixup.getLoc(), "fixup value must be 4-byte aligned.");
78
79 return (Value >> 2) & 0xffff;
80 case CSKY::fixup_csky_pcrel_imm26_scale2:
81 if (!isIntN(27, Value))
82 Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value.");
83 if (Value & 0x1)
84 Ctx.reportError(Fixup.getLoc(), "fixup value must be 2-byte aligned.");
85
86 return (Value >> 1) & 0x3ffffff;
87 case CSKY::fixup_csky_pcrel_imm18_scale2:
88 if (!isIntN(19, Value))
89 Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value.");
90 if (Value & 0x1)
91 Ctx.reportError(Fixup.getLoc(), "fixup value must be 2-byte aligned.");
92
93 return (Value >> 1) & 0x3ffff;
94 }
95 }
96
applyFixup(const MCAssembler & Asm,const MCFixup & Fixup,const MCValue & Target,MutableArrayRef<char> Data,uint64_t Value,bool IsResolved,const MCSubtargetInfo * STI) const97 void CSKYAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
98 const MCValue &Target,
99 MutableArrayRef<char> Data, uint64_t Value,
100 bool IsResolved,
101 const MCSubtargetInfo *STI) const {
102 MCFixupKind Kind = Fixup.getKind();
103 if (Kind >= FirstLiteralRelocationKind)
104 return;
105 MCContext &Ctx = Asm.getContext();
106 MCFixupKindInfo Info = getFixupKindInfo(Kind);
107 if (!Value)
108 return; // Doesn't change encoding.
109 // Apply any target-specific value adjustments.
110 Value = adjustFixupValue(Fixup, Value, Ctx);
111
112 // Shift the value into position.
113 Value <<= Info.TargetOffset;
114
115 unsigned Offset = Fixup.getOffset();
116 unsigned NumBytes = alignTo(Info.TargetSize + Info.TargetOffset, 8) / 8;
117
118 assert(Offset + NumBytes <= Data.size() && "Invalid fixup offset!");
119
120 // For each byte of the fragment that the fixup touches, mask in the
121 // bits from the fixup value.
122 bool IsLittleEndian = (Endian == support::little);
123
124 if (IsLittleEndian && (NumBytes == 4)) {
125 Data[Offset + 0] |= uint8_t((Value >> 16) & 0xff);
126 Data[Offset + 1] |= uint8_t((Value >> 24) & 0xff);
127 Data[Offset + 2] |= uint8_t(Value & 0xff);
128 Data[Offset + 3] |= uint8_t((Value >> 8) & 0xff);
129 } else {
130 for (unsigned I = 0; I != NumBytes; I++) {
131 unsigned Idx = IsLittleEndian ? I : (NumBytes - 1 - I);
132 Data[Offset + Idx] |= uint8_t((Value >> (I * 8)) & 0xff);
133 }
134 }
135 }
136
fixupNeedsRelaxation(const MCFixup & Fixup,uint64_t Value,const MCRelaxableFragment * DF,const MCAsmLayout & Layout) const137 bool CSKYAsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value,
138 const MCRelaxableFragment *DF,
139 const MCAsmLayout &Layout) const {
140 return false;
141 }
142
relaxInstruction(MCInst & Inst,const MCSubtargetInfo & STI) const143 void CSKYAsmBackend::relaxInstruction(MCInst &Inst,
144 const MCSubtargetInfo &STI) const {
145 llvm_unreachable("CSKYAsmBackend::relaxInstruction() unimplemented");
146 }
147
writeNopData(raw_ostream & OS,uint64_t Count) const148 bool CSKYAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count) const {
149 if (Count % 2)
150 return false;
151
152 // MOV32 r0, r0
153 while (Count >= 4) {
154 OS.write("\xc4\x00\x48\x20", 4);
155 Count -= 4;
156 }
157 // MOV16 r0, r0
158 if (Count)
159 OS.write("\x6c\x03", 2);
160
161 return true;
162 }
163
createCSKYAsmBackend(const Target & T,const MCSubtargetInfo & STI,const MCRegisterInfo & MRI,const MCTargetOptions & Options)164 MCAsmBackend *llvm::createCSKYAsmBackend(const Target &T,
165 const MCSubtargetInfo &STI,
166 const MCRegisterInfo &MRI,
167 const MCTargetOptions &Options) {
168 return new CSKYAsmBackend(STI, Options);
169 }
170