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> 24 CSKYAsmBackend::createObjectTargetWriter() const { 25 return createCSKYELFObjectWriter(); 26 } 27 28 const MCFixupKindInfo & 29 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_addr_hi16, {"fixup_csky_addr_hi16", 0, 32, 0}}, 34 {CSKY::Fixups::fixup_csky_addr_lo16, {"fixup_csky_addr_lo16", 0, 32, 0}}, 35 {CSKY::Fixups::fixup_csky_pcrel_imm16_scale2, 36 {"fixup_csky_pcrel_imm16_scale2", 0, 32, MCFixupKindInfo::FKF_IsPCRel}}, 37 {CSKY::Fixups::fixup_csky_pcrel_uimm16_scale4, 38 {"fixup_csky_pcrel_uimm16_scale4", 0, 32, 39 MCFixupKindInfo::FKF_IsPCRel | 40 MCFixupKindInfo::FKF_IsAlignedDownTo32Bits}}, 41 {CSKY::Fixups::fixup_csky_pcrel_uimm8_scale4, 42 {"fixup_csky_pcrel_uimm8_scale4", 0, 32, 43 MCFixupKindInfo::FKF_IsPCRel | 44 MCFixupKindInfo::FKF_IsAlignedDownTo32Bits}}, 45 {CSKY::Fixups::fixup_csky_pcrel_imm26_scale2, 46 {"fixup_csky_pcrel_imm26_scale2", 0, 32, MCFixupKindInfo::FKF_IsPCRel}}, 47 {CSKY::Fixups::fixup_csky_pcrel_imm18_scale2, 48 {"fixup_csky_pcrel_imm18_scale2", 0, 32, MCFixupKindInfo::FKF_IsPCRel}}, 49 {CSKY::Fixups::fixup_csky_got32, {"fixup_csky_got32", 0, 32, 0}}, 50 {CSKY::Fixups::fixup_csky_got_imm18_scale4, 51 {"fixup_csky_got_imm18_scale4", 0, 32, 0}}, 52 {CSKY::Fixups::fixup_csky_gotoff, {"fixup_csky_gotoff", 0, 32, 0}}, 53 {CSKY::Fixups::fixup_csky_gotpc, 54 {"fixup_csky_gotpc", 0, 32, MCFixupKindInfo::FKF_IsPCRel}}, 55 {CSKY::Fixups::fixup_csky_plt32, {"fixup_csky_plt32", 0, 32, 0}}, 56 {CSKY::Fixups::fixup_csky_plt_imm18_scale4, 57 {"fixup_csky_plt_imm18_scale4", 0, 32, 0}}, 58 {CSKY::Fixups::fixup_csky_pcrel_imm10_scale2, 59 {"fixup_csky_pcrel_imm10_scale2", 0, 16, MCFixupKindInfo::FKF_IsPCRel}}, 60 {CSKY::Fixups::fixup_csky_pcrel_uimm7_scale4, 61 {"fixup_csky_pcrel_uimm7_scale4", 0, 16, 62 MCFixupKindInfo::FKF_IsPCRel | 63 MCFixupKindInfo::FKF_IsAlignedDownTo32Bits}}, 64 {CSKY::Fixups::fixup_csky_doffset_imm18, 65 {"fixup_csky_doffset_imm18", 0, 18, 0}}, 66 {CSKY::Fixups::fixup_csky_doffset_imm18_scale2, 67 {"fixup_csky_doffset_imm18_scale2", 0, 18, 0}}, 68 {CSKY::Fixups::fixup_csky_doffset_imm18_scale4, 69 {"fixup_csky_doffset_imm18_scale4", 0, 18, 0}}}; 70 71 assert(Infos.size() == CSKY::NumTargetFixupKinds && 72 "Not all fixup kinds added to Infos array"); 73 74 if (FirstTargetFixupKind <= Kind && Kind < FirstLiteralRelocationKind) { 75 assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() && 76 "Invalid kind!"); 77 78 return Infos[Kind]; 79 } else if (Kind < FirstTargetFixupKind) { 80 return MCAsmBackend::getFixupKindInfo(Kind); 81 } else { 82 return MCAsmBackend::getFixupKindInfo(FK_NONE); 83 } 84 } 85 86 static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value, 87 MCContext &Ctx) { 88 switch (Fixup.getTargetKind()) { 89 default: 90 llvm_unreachable("Unknown fixup kind!"); 91 case CSKY::fixup_csky_got32: 92 case CSKY::fixup_csky_got_imm18_scale4: 93 case CSKY::fixup_csky_gotoff: 94 case CSKY::fixup_csky_gotpc: 95 case CSKY::fixup_csky_plt32: 96 case CSKY::fixup_csky_plt_imm18_scale4: 97 llvm_unreachable("Relocation should be unconditionally forced\n"); 98 case FK_Data_1: 99 case FK_Data_2: 100 case FK_Data_4: 101 case FK_Data_8: 102 return Value; 103 case CSKY::fixup_csky_addr32: 104 return Value & 0xffffffff; 105 case CSKY::fixup_csky_pcrel_imm16_scale2: 106 if (!isIntN(17, 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) & 0xffff; 112 case CSKY::fixup_csky_pcrel_uimm16_scale4: 113 if (!isUIntN(18, Value)) 114 Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value."); 115 if (Value & 0x3) 116 Ctx.reportError(Fixup.getLoc(), "fixup value must be 4-byte aligned."); 117 118 return (Value >> 2) & 0xffff; 119 case CSKY::fixup_csky_pcrel_imm26_scale2: 120 if (!isIntN(27, Value)) 121 Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value."); 122 if (Value & 0x1) 123 Ctx.reportError(Fixup.getLoc(), "fixup value must be 2-byte aligned."); 124 125 return (Value >> 1) & 0x3ffffff; 126 case CSKY::fixup_csky_pcrel_imm18_scale2: 127 if (!isIntN(19, Value)) 128 Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value."); 129 if (Value & 0x1) 130 Ctx.reportError(Fixup.getLoc(), "fixup value must be 2-byte aligned."); 131 132 return (Value >> 1) & 0x3ffff; 133 case CSKY::fixup_csky_pcrel_uimm8_scale4: { 134 if (!isUIntN(10, Value)) 135 Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value."); 136 if (Value & 0x3) 137 Ctx.reportError(Fixup.getLoc(), "fixup value must be 4-byte aligned."); 138 139 unsigned IMM4L = (Value >> 2) & 0xf; 140 unsigned IMM4H = (Value >> 6) & 0xf; 141 142 Value = (IMM4H << 21) | (IMM4L << 4); 143 return Value; 144 } 145 case CSKY::fixup_csky_pcrel_imm10_scale2: 146 if (!isIntN(11, Value)) 147 Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value."); 148 if (Value & 0x1) 149 Ctx.reportError(Fixup.getLoc(), "fixup value must be 2-byte aligned."); 150 151 return (Value >> 1) & 0x3ff; 152 case CSKY::fixup_csky_pcrel_uimm7_scale4: 153 if ((Value >> 2) > 0xfe) 154 Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value."); 155 if (Value & 0x3) 156 Ctx.reportError(Fixup.getLoc(), "fixup value must be 4-byte aligned."); 157 158 if ((Value >> 2) <= 0x7f) { 159 unsigned IMM5L = (Value >> 2) & 0x1f; 160 unsigned IMM2H = (Value >> 7) & 0x3; 161 162 Value = (1 << 12) | (IMM2H << 8) | IMM5L; 163 } else { 164 unsigned IMM5L = (~Value >> 2) & 0x1f; 165 unsigned IMM2H = (~Value >> 7) & 0x3; 166 167 Value = (IMM2H << 8) | IMM5L; 168 } 169 170 return Value; 171 } 172 } 173 174 bool CSKYAsmBackend::fixupNeedsRelaxationAdvanced(const MCFixup &Fixup, 175 bool Resolved, uint64_t Value, 176 const MCRelaxableFragment *DF, 177 const MCAsmLayout &Layout, 178 const bool WasForced) const { 179 // Return true if the symbol is actually unresolved. 180 // Resolved could be always false when shouldForceRelocation return true. 181 // We use !WasForced to indicate that the symbol is unresolved and not forced 182 // by shouldForceRelocation. 183 if (!Resolved && !WasForced) 184 return true; 185 186 int64_t Offset = int64_t(Value); 187 switch (Fixup.getTargetKind()) { 188 default: 189 return false; 190 case CSKY::fixup_csky_pcrel_imm10_scale2: 191 return !isShiftedInt<10, 1>(Offset); 192 case CSKY::fixup_csky_pcrel_imm16_scale2: 193 return !isShiftedInt<16, 1>(Offset); 194 case CSKY::fixup_csky_pcrel_imm26_scale2: 195 return !isShiftedInt<26, 1>(Offset); 196 case CSKY::fixup_csky_pcrel_uimm7_scale4: 197 return ((Value >> 2) > 0xfe) || (Value & 0x3); 198 } 199 } 200 201 void CSKYAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, 202 const MCValue &Target, 203 MutableArrayRef<char> Data, uint64_t Value, 204 bool IsResolved, 205 const MCSubtargetInfo *STI) const { 206 MCFixupKind Kind = Fixup.getKind(); 207 if (Kind >= FirstLiteralRelocationKind) 208 return; 209 MCContext &Ctx = Asm.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 == support::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(const MCInst &Inst, 243 const MCSubtargetInfo &STI) const { 244 switch (Inst.getOpcode()) { 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 MCAssembler &Asm, 264 const MCFixup &Fixup, 265 const MCValue &Target) { 266 if (Fixup.getKind() >= FirstLiteralRelocationKind) 267 return true; 268 switch (Fixup.getTargetKind()) { 269 default: 270 break; 271 case CSKY::fixup_csky_got32: 272 case CSKY::fixup_csky_got_imm18_scale4: 273 case CSKY::fixup_csky_gotoff: 274 case CSKY::fixup_csky_gotpc: 275 case CSKY::fixup_csky_plt32: 276 case CSKY::fixup_csky_plt_imm18_scale4: 277 case CSKY::fixup_csky_doffset_imm18: 278 case CSKY::fixup_csky_doffset_imm18_scale2: 279 case CSKY::fixup_csky_doffset_imm18_scale4: 280 return true; 281 } 282 283 return false; 284 } 285 286 bool CSKYAsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value, 287 const MCRelaxableFragment *DF, 288 const MCAsmLayout &Layout) const { 289 return false; 290 } 291 292 void CSKYAsmBackend::relaxInstruction(MCInst &Inst, 293 const MCSubtargetInfo &STI) const { 294 MCInst Res; 295 296 switch (Inst.getOpcode()) { 297 default: 298 LLVM_DEBUG(Inst.dump()); 299 llvm_unreachable("Opcode not expected!"); 300 case CSKY::LRW16: 301 Res.setOpcode(CSKY::LRW32); 302 Res.addOperand(Inst.getOperand(0)); 303 Res.addOperand(Inst.getOperand(1)); 304 break; 305 case CSKY::BR16: 306 Res.setOpcode(CSKY::BR32); 307 Res.addOperand(Inst.getOperand(0)); 308 break; 309 case CSKY::JBSR32: 310 Res.setOpcode(CSKY::JSRI32); 311 Res.addOperand(Inst.getOperand(1)); 312 break; 313 case CSKY::JBR32: 314 Res.setOpcode(CSKY::JMPI32); 315 Res.addOperand(Inst.getOperand(1)); 316 break; 317 case CSKY::JBT32: 318 case CSKY::JBF32: 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)); 323 break; 324 case CSKY::JBR16: 325 Res.setOpcode(CSKY::JBR32); 326 Res.addOperand(Inst.getOperand(0)); 327 Res.addOperand(Inst.getOperand(1)); 328 break; 329 case CSKY::JBT16: 330 case CSKY::JBF16: 331 // ck801 332 unsigned opcode; 333 if (STI.hasFeature(CSKY::HasE2)) 334 opcode = Inst.getOpcode() == CSKY::JBT16 ? CSKY::JBT32 : CSKY::JBF32; 335 else 336 opcode = Inst.getOpcode() == CSKY::JBT16 ? CSKY::JBT_E : CSKY::JBF_E; 337 338 Res.setOpcode(opcode); 339 Res.addOperand(Inst.getOperand(0)); 340 Res.addOperand(Inst.getOperand(1)); 341 Res.addOperand(Inst.getOperand(2)); 342 break; 343 } 344 Inst = std::move(Res); 345 } 346 347 bool CSKYAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count, 348 const MCSubtargetInfo *STI) const { 349 OS.write_zeros(Count); 350 return true; 351 } 352 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); 358 } 359