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/MCAssembler.h" 13 #include "llvm/MC/MCContext.h" 14 #include "llvm/MC/MCObjectWriter.h" 15 #include "llvm/MC/MCValue.h" 16 #include "llvm/Support/Debug.h" 17 18 #define DEBUG_TYPE "csky-asmbackend" 19 20 using namespace llvm; 21 22 std::unique_ptr<MCObjectTargetWriter> 23 CSKYAsmBackend::createObjectTargetWriter() const { 24 return createCSKYELFObjectWriter(); 25 } 26 27 MCFixupKindInfo CSKYAsmBackend::getFixupKindInfo(MCFixupKind Kind) const { 28 29 static llvm::DenseMap<unsigned, MCFixupKindInfo> Infos = { 30 {CSKY::Fixups::fixup_csky_addr32, {"fixup_csky_addr32", 0, 32, 0}}, 31 {CSKY::Fixups::fixup_csky_addr_hi16, {"fixup_csky_addr_hi16", 0, 32, 0}}, 32 {CSKY::Fixups::fixup_csky_addr_lo16, {"fixup_csky_addr_lo16", 0, 32, 0}}, 33 {CSKY::Fixups::fixup_csky_pcrel_imm16_scale2, 34 {"fixup_csky_pcrel_imm16_scale2", 0, 32, 0}}, 35 {CSKY::Fixups::fixup_csky_pcrel_uimm16_scale4, 36 {"fixup_csky_pcrel_uimm16_scale4", 0, 32, 0}}, 37 {CSKY::Fixups::fixup_csky_pcrel_uimm8_scale4, 38 {"fixup_csky_pcrel_uimm8_scale4", 0, 32, 0}}, 39 {CSKY::Fixups::fixup_csky_pcrel_imm26_scale2, 40 {"fixup_csky_pcrel_imm26_scale2", 0, 32, 0}}, 41 {CSKY::Fixups::fixup_csky_pcrel_imm18_scale2, 42 {"fixup_csky_pcrel_imm18_scale2", 0, 32, 0}}, 43 {CSKY::Fixups::fixup_csky_got32, {"fixup_csky_got32", 0, 32, 0}}, 44 {CSKY::Fixups::fixup_csky_got_imm18_scale4, 45 {"fixup_csky_got_imm18_scale4", 0, 32, 0}}, 46 {CSKY::Fixups::fixup_csky_gotoff, {"fixup_csky_gotoff", 0, 32, 0}}, 47 {CSKY::Fixups::fixup_csky_gotpc, {"fixup_csky_gotpc", 0, 32, 0}}, 48 {CSKY::Fixups::fixup_csky_plt32, {"fixup_csky_plt32", 0, 32, 0}}, 49 {CSKY::Fixups::fixup_csky_plt_imm18_scale4, 50 {"fixup_csky_plt_imm18_scale4", 0, 32, 0}}, 51 {CSKY::Fixups::fixup_csky_pcrel_imm10_scale2, 52 {"fixup_csky_pcrel_imm10_scale2", 0, 16, 0}}, 53 {CSKY::Fixups::fixup_csky_pcrel_uimm7_scale4, 54 {"fixup_csky_pcrel_uimm7_scale4", 0, 16, 0}}, 55 {CSKY::Fixups::fixup_csky_doffset_imm18, 56 {"fixup_csky_doffset_imm18", 0, 18, 0}}, 57 {CSKY::Fixups::fixup_csky_doffset_imm18_scale2, 58 {"fixup_csky_doffset_imm18_scale2", 0, 18, 0}}, 59 {CSKY::Fixups::fixup_csky_doffset_imm18_scale4, 60 {"fixup_csky_doffset_imm18_scale4", 0, 18, 0}}}; 61 62 assert(Infos.size() == CSKY::NumTargetFixupKinds && 63 "Not all fixup kinds added to Infos array"); 64 65 if (mc::isRelocation(Kind)) 66 return {}; 67 if (Kind < FirstTargetFixupKind) 68 return MCAsmBackend::getFixupKindInfo(Kind); 69 return Infos[Kind]; 70 } 71 72 static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value, 73 MCContext &Ctx) { 74 switch (Fixup.getKind()) { 75 default: 76 llvm_unreachable("Unknown fixup kind!"); 77 case CSKY::fixup_csky_got32: 78 case CSKY::fixup_csky_got_imm18_scale4: 79 case CSKY::fixup_csky_gotoff: 80 case CSKY::fixup_csky_gotpc: 81 case CSKY::fixup_csky_plt32: 82 case CSKY::fixup_csky_plt_imm18_scale4: 83 llvm_unreachable("Relocation should be unconditionally forced\n"); 84 case FK_Data_1: 85 case FK_Data_2: 86 case FK_Data_4: 87 case FK_Data_8: 88 return Value; 89 case CSKY::fixup_csky_addr32: 90 return Value & 0xffffffff; 91 case CSKY::fixup_csky_pcrel_imm16_scale2: 92 if (!isIntN(17, Value)) 93 Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value."); 94 if (Value & 0x1) 95 Ctx.reportError(Fixup.getLoc(), "fixup value must be 2-byte aligned."); 96 97 return (Value >> 1) & 0xffff; 98 case CSKY::fixup_csky_pcrel_uimm16_scale4: 99 if (!isUIntN(18, Value)) 100 Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value."); 101 if (Value & 0x3) 102 Ctx.reportError(Fixup.getLoc(), "fixup value must be 4-byte aligned."); 103 104 return (Value >> 2) & 0xffff; 105 case CSKY::fixup_csky_pcrel_imm26_scale2: 106 if (!isIntN(27, Value)) 107 Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value."); 108 if (Value & 0x1) 109 Ctx.reportError(Fixup.getLoc(), "fixup value must be 2-byte aligned."); 110 111 return (Value >> 1) & 0x3ffffff; 112 case CSKY::fixup_csky_pcrel_imm18_scale2: 113 if (!isIntN(19, Value)) 114 Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value."); 115 if (Value & 0x1) 116 Ctx.reportError(Fixup.getLoc(), "fixup value must be 2-byte aligned."); 117 118 return (Value >> 1) & 0x3ffff; 119 case CSKY::fixup_csky_pcrel_uimm8_scale4: { 120 if (!isUIntN(10, Value)) 121 Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value."); 122 if (Value & 0x3) 123 Ctx.reportError(Fixup.getLoc(), "fixup value must be 4-byte aligned."); 124 125 unsigned IMM4L = (Value >> 2) & 0xf; 126 unsigned IMM4H = (Value >> 6) & 0xf; 127 128 Value = (IMM4H << 21) | (IMM4L << 4); 129 return Value; 130 } 131 case CSKY::fixup_csky_pcrel_imm10_scale2: 132 if (!isIntN(11, Value)) 133 Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value."); 134 if (Value & 0x1) 135 Ctx.reportError(Fixup.getLoc(), "fixup value must be 2-byte aligned."); 136 137 return (Value >> 1) & 0x3ff; 138 case CSKY::fixup_csky_pcrel_uimm7_scale4: 139 if ((Value >> 2) > 0xfe) 140 Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value."); 141 if (Value & 0x3) 142 Ctx.reportError(Fixup.getLoc(), "fixup value must be 4-byte aligned."); 143 144 if ((Value >> 2) <= 0x7f) { 145 unsigned IMM5L = (Value >> 2) & 0x1f; 146 unsigned IMM2H = (Value >> 7) & 0x3; 147 148 Value = (1 << 12) | (IMM2H << 8) | IMM5L; 149 } else { 150 unsigned IMM5L = (~Value >> 2) & 0x1f; 151 unsigned IMM2H = (~Value >> 7) & 0x3; 152 153 Value = (IMM2H << 8) | IMM5L; 154 } 155 156 return Value; 157 } 158 } 159 160 bool CSKYAsmBackend::fixupNeedsRelaxationAdvanced(const MCFixup &Fixup, 161 const MCValue &, 162 uint64_t Value, 163 bool Resolved) const { 164 // Return true if the symbol is unresolved. 165 if (!Resolved) 166 return true; 167 168 int64_t Offset = int64_t(Value); 169 switch (Fixup.getKind()) { 170 default: 171 return false; 172 case CSKY::fixup_csky_pcrel_imm10_scale2: 173 return !isShiftedInt<10, 1>(Offset); 174 case CSKY::fixup_csky_pcrel_imm16_scale2: 175 return !isShiftedInt<16, 1>(Offset); 176 case CSKY::fixup_csky_pcrel_imm26_scale2: 177 return !isShiftedInt<26, 1>(Offset); 178 case CSKY::fixup_csky_pcrel_uimm7_scale4: 179 return ((Value >> 2) > 0xfe) || (Value & 0x3); 180 } 181 } 182 183 std::optional<bool> CSKYAsmBackend::evaluateFixup(const MCFragment &F, 184 MCFixup &Fixup, MCValue &, 185 uint64_t &Value) { 186 // For a few PC-relative fixups, offsets need to be aligned down. We 187 // compensate here because the default handler's `Value` decrement doesn't 188 // account for this alignment. 189 switch (Fixup.getKind()) { 190 case CSKY::fixup_csky_pcrel_uimm16_scale4: 191 case CSKY::fixup_csky_pcrel_uimm8_scale4: 192 case CSKY::fixup_csky_pcrel_uimm7_scale4: 193 Value = (Asm->getFragmentOffset(F) + Fixup.getOffset()) % 4; 194 } 195 return {}; 196 } 197 198 void CSKYAsmBackend::applyFixup(const MCFragment &F, const MCFixup &Fixup, 199 const MCValue &Target, 200 MutableArrayRef<char> Data, uint64_t Value, 201 bool IsResolved) { 202 if (IsResolved && shouldForceRelocation(Fixup, Target)) 203 IsResolved = false; 204 maybeAddReloc(F, Fixup, Target, Value, IsResolved); 205 206 MCFixupKind Kind = Fixup.getKind(); 207 if (mc::isRelocation(Kind)) 208 return; 209 MCContext &Ctx = getContext(); 210 MCFixupKindInfo Info = getFixupKindInfo(Kind); 211 if (!Value) 212 return; // Doesn't change encoding. 213 // Apply any target-specific value adjustments. 214 Value = adjustFixupValue(Fixup, Value, Ctx); 215 216 // Shift the value into position. 217 Value <<= Info.TargetOffset; 218 219 unsigned Offset = Fixup.getOffset(); 220 unsigned NumBytes = alignTo(Info.TargetSize + Info.TargetOffset, 8) / 8; 221 222 assert(Offset + NumBytes <= Data.size() && "Invalid fixup offset!"); 223 224 // For each byte of the fragment that the fixup touches, mask in the 225 // bits from the fixup value. 226 bool IsLittleEndian = (Endian == llvm::endianness::little); 227 bool IsInstFixup = (Kind >= FirstTargetFixupKind); 228 229 if (IsLittleEndian && IsInstFixup && (NumBytes == 4)) { 230 Data[Offset + 0] |= uint8_t((Value >> 16) & 0xff); 231 Data[Offset + 1] |= uint8_t((Value >> 24) & 0xff); 232 Data[Offset + 2] |= uint8_t(Value & 0xff); 233 Data[Offset + 3] |= uint8_t((Value >> 8) & 0xff); 234 } else { 235 for (unsigned I = 0; I != NumBytes; I++) { 236 unsigned Idx = IsLittleEndian ? I : (NumBytes - 1 - I); 237 Data[Offset + Idx] |= uint8_t((Value >> (I * 8)) & 0xff); 238 } 239 } 240 } 241 242 bool CSKYAsmBackend::mayNeedRelaxation(unsigned Opcode, ArrayRef<MCOperand>, 243 const MCSubtargetInfo &STI) const { 244 switch (Opcode) { 245 default: 246 return false; 247 case CSKY::JBR32: 248 case CSKY::JBT32: 249 case CSKY::JBF32: 250 case CSKY::JBSR32: 251 if (!STI.hasFeature(CSKY::Has2E3)) 252 return false; 253 return true; 254 case CSKY::JBR16: 255 case CSKY::JBT16: 256 case CSKY::JBF16: 257 case CSKY::LRW16: 258 case CSKY::BR16: 259 return true; 260 } 261 } 262 263 bool CSKYAsmBackend::shouldForceRelocation(const MCFixup &Fixup, 264 const MCValue &Target /*STI*/) { 265 if (Target.getSpecifier()) 266 return true; 267 switch (Fixup.getKind()) { 268 default: 269 break; 270 case CSKY::fixup_csky_doffset_imm18: 271 case CSKY::fixup_csky_doffset_imm18_scale2: 272 case CSKY::fixup_csky_doffset_imm18_scale4: 273 return true; 274 } 275 276 return false; 277 } 278 279 bool CSKYAsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup, 280 uint64_t Value) const { 281 return false; 282 } 283 284 void CSKYAsmBackend::relaxInstruction(MCInst &Inst, 285 const MCSubtargetInfo &STI) const { 286 MCInst Res; 287 288 switch (Inst.getOpcode()) { 289 default: 290 LLVM_DEBUG(Inst.dump()); 291 llvm_unreachable("Opcode not expected!"); 292 case CSKY::LRW16: 293 Res.setOpcode(CSKY::LRW32); 294 Res.addOperand(Inst.getOperand(0)); 295 Res.addOperand(Inst.getOperand(1)); 296 break; 297 case CSKY::BR16: 298 Res.setOpcode(CSKY::BR32); 299 Res.addOperand(Inst.getOperand(0)); 300 break; 301 case CSKY::JBSR32: 302 Res.setOpcode(CSKY::JSRI32); 303 Res.addOperand(Inst.getOperand(1)); 304 break; 305 case CSKY::JBR32: 306 Res.setOpcode(CSKY::JMPI32); 307 Res.addOperand(Inst.getOperand(1)); 308 break; 309 case CSKY::JBT32: 310 case CSKY::JBF32: 311 Res.setOpcode(Inst.getOpcode() == CSKY::JBT32 ? CSKY::JBT_E : CSKY::JBF_E); 312 Res.addOperand(Inst.getOperand(0)); 313 Res.addOperand(Inst.getOperand(1)); 314 Res.addOperand(Inst.getOperand(2)); 315 break; 316 case CSKY::JBR16: 317 Res.setOpcode(CSKY::JBR32); 318 Res.addOperand(Inst.getOperand(0)); 319 Res.addOperand(Inst.getOperand(1)); 320 break; 321 case CSKY::JBT16: 322 case CSKY::JBF16: 323 // ck801 324 unsigned opcode; 325 if (STI.hasFeature(CSKY::HasE2)) 326 opcode = Inst.getOpcode() == CSKY::JBT16 ? CSKY::JBT32 : CSKY::JBF32; 327 else 328 opcode = Inst.getOpcode() == CSKY::JBT16 ? CSKY::JBT_E : CSKY::JBF_E; 329 330 Res.setOpcode(opcode); 331 Res.addOperand(Inst.getOperand(0)); 332 Res.addOperand(Inst.getOperand(1)); 333 Res.addOperand(Inst.getOperand(2)); 334 break; 335 } 336 Inst = std::move(Res); 337 } 338 339 bool CSKYAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count, 340 const MCSubtargetInfo *STI) const { 341 OS.write_zeros(Count); 342 return true; 343 } 344 345 MCAsmBackend *llvm::createCSKYAsmBackend(const Target &T, 346 const MCSubtargetInfo &STI, 347 const MCRegisterInfo &MRI, 348 const MCTargetOptions &Options) { 349 return new CSKYAsmBackend(STI, Options); 350 } 351