351 lines · cpp
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-exception6//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 20using namespace llvm;21 22std::unique_ptr<MCObjectTargetWriter>23CSKYAsmBackend::createObjectTargetWriter() const {24 return createCSKYELFObjectWriter();25}26 27MCFixupKindInfo 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 72static 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 160bool CSKYAsmBackend::fixupNeedsRelaxationAdvanced(const MCFragment &,161 const MCFixup &Fixup,162 const MCValue &,163 uint64_t Value,164 bool Resolved) const {165 // Return true if the symbol is unresolved.166 if (!Resolved)167 return true;168 169 int64_t Offset = int64_t(Value);170 switch (Fixup.getKind()) {171 default:172 return false;173 case CSKY::fixup_csky_pcrel_imm10_scale2:174 return !isShiftedInt<10, 1>(Offset);175 case CSKY::fixup_csky_pcrel_imm16_scale2:176 return !isShiftedInt<16, 1>(Offset);177 case CSKY::fixup_csky_pcrel_imm26_scale2:178 return !isShiftedInt<26, 1>(Offset);179 case CSKY::fixup_csky_pcrel_uimm7_scale4:180 return ((Value >> 2) > 0xfe) || (Value & 0x3);181 }182}183 184std::optional<bool> CSKYAsmBackend::evaluateFixup(const MCFragment &F,185 MCFixup &Fixup, MCValue &,186 uint64_t &Value) {187 // For a few PC-relative fixups, offsets need to be aligned down. We188 // compensate here because the default handler's `Value` decrement doesn't189 // account for this alignment.190 switch (Fixup.getKind()) {191 case CSKY::fixup_csky_pcrel_uimm16_scale4:192 case CSKY::fixup_csky_pcrel_uimm8_scale4:193 case CSKY::fixup_csky_pcrel_uimm7_scale4:194 Value = (Asm->getFragmentOffset(F) + Fixup.getOffset()) % 4;195 }196 return {};197}198 199void CSKYAsmBackend::applyFixup(const MCFragment &F, const MCFixup &Fixup,200 const MCValue &Target, uint8_t *Data,201 uint64_t Value, 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 NumBytes = alignTo(Info.TargetSize + Info.TargetOffset, 8) / 8;220 221 assert(Fixup.getOffset() + NumBytes <= F.getSize() &&222 "Invalid fixup offset!");223 224 // For each byte of the fragment that the fixup touches, mask in the225 // 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[0] |= uint8_t((Value >> 16) & 0xff);231 Data[1] |= uint8_t((Value >> 24) & 0xff);232 Data[2] |= uint8_t(Value & 0xff);233 Data[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[Idx] |= uint8_t((Value >> (I * 8)) & 0xff);238 }239 }240}241 242bool 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 263bool 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 279bool CSKYAsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup,280 uint64_t Value) const {281 return false;282}283 284void 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 // ck801324 unsigned opcode;325 if (STI.hasFeature(CSKY::HasE2))326 opcode = Inst.getOpcode() == CSKY::JBT16 ? CSKY::JBT32 : CSKY::JBF32;327 else328 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 339bool CSKYAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count,340 const MCSubtargetInfo *STI) const {341 OS.write_zeros(Count);342 return true;343}344 345MCAsmBackend *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