diff options
Diffstat (limited to 'contrib/llvm-project/llvm/lib/Target/CSKY/MCTargetDesc/CSKYAsmBackend.cpp')
| -rw-r--r-- | contrib/llvm-project/llvm/lib/Target/CSKY/MCTargetDesc/CSKYAsmBackend.cpp | 358 |
1 files changed, 358 insertions, 0 deletions
diff --git a/contrib/llvm-project/llvm/lib/Target/CSKY/MCTargetDesc/CSKYAsmBackend.cpp b/contrib/llvm-project/llvm/lib/Target/CSKY/MCTargetDesc/CSKYAsmBackend.cpp new file mode 100644 index 000000000000..4171a97e9000 --- /dev/null +++ b/contrib/llvm-project/llvm/lib/Target/CSKY/MCTargetDesc/CSKYAsmBackend.cpp @@ -0,0 +1,358 @@ +//===-- CSKYAsmBackend.cpp - CSKY Assembler Backend -----------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "CSKYAsmBackend.h" +#include "MCTargetDesc/CSKYMCTargetDesc.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/MC/MCAsmLayout.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCFixupKindInfo.h" +#include "llvm/MC/MCObjectWriter.h" +#include "llvm/Support/Debug.h" + +#define DEBUG_TYPE "csky-asmbackend" + +using namespace llvm; + +std::unique_ptr<MCObjectTargetWriter> +CSKYAsmBackend::createObjectTargetWriter() const { + return createCSKYELFObjectWriter(); +} + +const MCFixupKindInfo & +CSKYAsmBackend::getFixupKindInfo(MCFixupKind Kind) const { + + static llvm::DenseMap<unsigned, MCFixupKindInfo> Infos = { + {CSKY::Fixups::fixup_csky_addr32, {"fixup_csky_addr32", 0, 32, 0}}, + {CSKY::Fixups::fixup_csky_addr_hi16, {"fixup_csky_addr_hi16", 0, 32, 0}}, + {CSKY::Fixups::fixup_csky_addr_lo16, {"fixup_csky_addr_lo16", 0, 32, 0}}, + {CSKY::Fixups::fixup_csky_pcrel_imm16_scale2, + {"fixup_csky_pcrel_imm16_scale2", 0, 32, MCFixupKindInfo::FKF_IsPCRel}}, + {CSKY::Fixups::fixup_csky_pcrel_uimm16_scale4, + {"fixup_csky_pcrel_uimm16_scale4", 0, 32, + MCFixupKindInfo::FKF_IsPCRel | + MCFixupKindInfo::FKF_IsAlignedDownTo32Bits}}, + {CSKY::Fixups::fixup_csky_pcrel_uimm8_scale4, + {"fixup_csky_pcrel_uimm8_scale4", 0, 32, + MCFixupKindInfo::FKF_IsPCRel | + MCFixupKindInfo::FKF_IsAlignedDownTo32Bits}}, + {CSKY::Fixups::fixup_csky_pcrel_imm26_scale2, + {"fixup_csky_pcrel_imm26_scale2", 0, 32, MCFixupKindInfo::FKF_IsPCRel}}, + {CSKY::Fixups::fixup_csky_pcrel_imm18_scale2, + {"fixup_csky_pcrel_imm18_scale2", 0, 32, MCFixupKindInfo::FKF_IsPCRel}}, + {CSKY::Fixups::fixup_csky_got32, {"fixup_csky_got32", 0, 32, 0}}, + {CSKY::Fixups::fixup_csky_got_imm18_scale4, + {"fixup_csky_got_imm18_scale4", 0, 32, 0}}, + {CSKY::Fixups::fixup_csky_gotoff, {"fixup_csky_gotoff", 0, 32, 0}}, + {CSKY::Fixups::fixup_csky_gotpc, + {"fixup_csky_gotpc", 0, 32, MCFixupKindInfo::FKF_IsPCRel}}, + {CSKY::Fixups::fixup_csky_plt32, {"fixup_csky_plt32", 0, 32, 0}}, + {CSKY::Fixups::fixup_csky_plt_imm18_scale4, + {"fixup_csky_plt_imm18_scale4", 0, 32, 0}}, + {CSKY::Fixups::fixup_csky_pcrel_imm10_scale2, + {"fixup_csky_pcrel_imm10_scale2", 0, 16, MCFixupKindInfo::FKF_IsPCRel}}, + {CSKY::Fixups::fixup_csky_pcrel_uimm7_scale4, + {"fixup_csky_pcrel_uimm7_scale4", 0, 16, + MCFixupKindInfo::FKF_IsPCRel | + MCFixupKindInfo::FKF_IsAlignedDownTo32Bits}}, + {CSKY::Fixups::fixup_csky_doffset_imm18, + {"fixup_csky_doffset_imm18", 0, 18, 0}}, + {CSKY::Fixups::fixup_csky_doffset_imm18_scale2, + {"fixup_csky_doffset_imm18_scale2", 0, 18, 0}}, + {CSKY::Fixups::fixup_csky_doffset_imm18_scale4, + {"fixup_csky_doffset_imm18_scale4", 0, 18, 0}}}; + + assert(Infos.size() == CSKY::NumTargetFixupKinds && + "Not all fixup kinds added to Infos array"); + + if (FirstTargetFixupKind <= Kind && Kind < FirstLiteralRelocationKind) { + assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() && + "Invalid kind!"); + + return Infos[Kind]; + } else if (Kind < FirstTargetFixupKind) { + return MCAsmBackend::getFixupKindInfo(Kind); + } else { + return MCAsmBackend::getFixupKindInfo(FK_NONE); + } +} + +static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value, + MCContext &Ctx) { + switch (Fixup.getTargetKind()) { + default: + llvm_unreachable("Unknown fixup kind!"); + case CSKY::fixup_csky_got32: + case CSKY::fixup_csky_got_imm18_scale4: + case CSKY::fixup_csky_gotoff: + case CSKY::fixup_csky_gotpc: + case CSKY::fixup_csky_plt32: + case CSKY::fixup_csky_plt_imm18_scale4: + llvm_unreachable("Relocation should be unconditionally forced\n"); + case FK_Data_1: + case FK_Data_2: + case FK_Data_4: + case FK_Data_8: + return Value; + case CSKY::fixup_csky_addr32: + return Value & 0xffffffff; + case CSKY::fixup_csky_pcrel_imm16_scale2: + if (!isIntN(17, Value)) + Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value."); + if (Value & 0x1) + Ctx.reportError(Fixup.getLoc(), "fixup value must be 2-byte aligned."); + + return (Value >> 1) & 0xffff; + case CSKY::fixup_csky_pcrel_uimm16_scale4: + if (!isUIntN(18, Value)) + Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value."); + if (Value & 0x3) + Ctx.reportError(Fixup.getLoc(), "fixup value must be 4-byte aligned."); + + return (Value >> 2) & 0xffff; + case CSKY::fixup_csky_pcrel_imm26_scale2: + if (!isIntN(27, Value)) + Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value."); + if (Value & 0x1) + Ctx.reportError(Fixup.getLoc(), "fixup value must be 2-byte aligned."); + + return (Value >> 1) & 0x3ffffff; + case CSKY::fixup_csky_pcrel_imm18_scale2: + if (!isIntN(19, Value)) + Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value."); + if (Value & 0x1) + Ctx.reportError(Fixup.getLoc(), "fixup value must be 2-byte aligned."); + + return (Value >> 1) & 0x3ffff; + case CSKY::fixup_csky_pcrel_uimm8_scale4: { + if (!isUIntN(10, Value)) + Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value."); + if (Value & 0x3) + Ctx.reportError(Fixup.getLoc(), "fixup value must be 4-byte aligned."); + + unsigned IMM4L = (Value >> 2) & 0xf; + unsigned IMM4H = (Value >> 6) & 0xf; + + Value = (IMM4H << 21) | (IMM4L << 4); + return Value; + } + case CSKY::fixup_csky_pcrel_imm10_scale2: + if (!isIntN(11, Value)) + Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value."); + if (Value & 0x1) + Ctx.reportError(Fixup.getLoc(), "fixup value must be 2-byte aligned."); + + return (Value >> 1) & 0x3ff; + case CSKY::fixup_csky_pcrel_uimm7_scale4: + if ((Value >> 2) > 0xfe) + Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value."); + if (Value & 0x3) + Ctx.reportError(Fixup.getLoc(), "fixup value must be 4-byte aligned."); + + if ((Value >> 2) <= 0x7f) { + unsigned IMM5L = (Value >> 2) & 0x1f; + unsigned IMM2H = (Value >> 7) & 0x3; + + Value = (1 << 12) | (IMM2H << 8) | IMM5L; + } else { + unsigned IMM5L = (~Value >> 2) & 0x1f; + unsigned IMM2H = (~Value >> 7) & 0x3; + + Value = (IMM2H << 8) | IMM5L; + } + + return Value; + } +} + +bool CSKYAsmBackend::fixupNeedsRelaxationAdvanced(const MCFixup &Fixup, + bool Resolved, uint64_t Value, + const MCRelaxableFragment *DF, + const MCAsmLayout &Layout, + const bool WasForced) const { + // Return true if the symbol is actually unresolved. + // Resolved could be always false when shouldForceRelocation return true. + // We use !WasForced to indicate that the symbol is unresolved and not forced + // by shouldForceRelocation. + if (!Resolved && !WasForced) + return true; + + int64_t Offset = int64_t(Value); + switch (Fixup.getTargetKind()) { + default: + return false; + case CSKY::fixup_csky_pcrel_imm10_scale2: + return !isShiftedInt<10, 1>(Offset); + case CSKY::fixup_csky_pcrel_imm16_scale2: + return !isShiftedInt<16, 1>(Offset); + case CSKY::fixup_csky_pcrel_imm26_scale2: + return !isShiftedInt<26, 1>(Offset); + case CSKY::fixup_csky_pcrel_uimm7_scale4: + return ((Value >> 2) > 0xfe) || (Value & 0x3); + } +} + +void CSKYAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, + const MCValue &Target, + MutableArrayRef<char> Data, uint64_t Value, + bool IsResolved, + const MCSubtargetInfo *STI) const { + MCFixupKind Kind = Fixup.getKind(); + if (Kind >= FirstLiteralRelocationKind) + return; + MCContext &Ctx = Asm.getContext(); + MCFixupKindInfo Info = getFixupKindInfo(Kind); + if (!Value) + return; // Doesn't change encoding. + // Apply any target-specific value adjustments. + Value = adjustFixupValue(Fixup, Value, Ctx); + + // Shift the value into position. + Value <<= Info.TargetOffset; + + unsigned Offset = Fixup.getOffset(); + unsigned NumBytes = alignTo(Info.TargetSize + Info.TargetOffset, 8) / 8; + + assert(Offset + NumBytes <= Data.size() && "Invalid fixup offset!"); + + // For each byte of the fragment that the fixup touches, mask in the + // bits from the fixup value. + bool IsLittleEndian = (Endian == support::little); + bool IsInstFixup = (Kind >= FirstTargetFixupKind); + + if (IsLittleEndian && IsInstFixup && (NumBytes == 4)) { + Data[Offset + 0] |= uint8_t((Value >> 16) & 0xff); + Data[Offset + 1] |= uint8_t((Value >> 24) & 0xff); + Data[Offset + 2] |= uint8_t(Value & 0xff); + Data[Offset + 3] |= uint8_t((Value >> 8) & 0xff); + } else { + for (unsigned I = 0; I != NumBytes; I++) { + unsigned Idx = IsLittleEndian ? I : (NumBytes - 1 - I); + Data[Offset + Idx] |= uint8_t((Value >> (I * 8)) & 0xff); + } + } +} + +bool CSKYAsmBackend::mayNeedRelaxation(const MCInst &Inst, + const MCSubtargetInfo &STI) const { + switch (Inst.getOpcode()) { + default: + return false; + case CSKY::JBR32: + case CSKY::JBT32: + case CSKY::JBF32: + case CSKY::JBSR32: + if (!STI.getFeatureBits()[CSKY::Has2E3]) + return false; + return true; + case CSKY::JBR16: + case CSKY::JBT16: + case CSKY::JBF16: + case CSKY::LRW16: + case CSKY::BR16: + return true; + } +} + +bool CSKYAsmBackend::shouldForceRelocation(const MCAssembler &Asm, + const MCFixup &Fixup, + const MCValue &Target) { + if (Fixup.getKind() >= FirstLiteralRelocationKind) + return true; + switch (Fixup.getTargetKind()) { + default: + break; + case CSKY::fixup_csky_got32: + case CSKY::fixup_csky_got_imm18_scale4: + case CSKY::fixup_csky_gotoff: + case CSKY::fixup_csky_gotpc: + case CSKY::fixup_csky_plt32: + case CSKY::fixup_csky_plt_imm18_scale4: + case CSKY::fixup_csky_doffset_imm18: + case CSKY::fixup_csky_doffset_imm18_scale2: + case CSKY::fixup_csky_doffset_imm18_scale4: + return true; + } + + return false; +} + +bool CSKYAsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value, + const MCRelaxableFragment *DF, + const MCAsmLayout &Layout) const { + return false; +} + +void CSKYAsmBackend::relaxInstruction(MCInst &Inst, + const MCSubtargetInfo &STI) const { + MCInst Res; + + switch (Inst.getOpcode()) { + default: + LLVM_DEBUG(Inst.dump()); + llvm_unreachable("Opcode not expected!"); + case CSKY::LRW16: + Res.setOpcode(CSKY::LRW32); + Res.addOperand(Inst.getOperand(0)); + Res.addOperand(Inst.getOperand(1)); + break; + case CSKY::BR16: + Res.setOpcode(CSKY::BR32); + Res.addOperand(Inst.getOperand(0)); + break; + case CSKY::JBSR32: + Res.setOpcode(CSKY::JSRI32); + Res.addOperand(Inst.getOperand(1)); + break; + case CSKY::JBR32: + Res.setOpcode(CSKY::JMPI32); + Res.addOperand(Inst.getOperand(1)); + break; + case CSKY::JBT32: + case CSKY::JBF32: + Res.setOpcode(Inst.getOpcode() == CSKY::JBT32 ? CSKY::JBT_E : CSKY::JBF_E); + Res.addOperand(Inst.getOperand(0)); + Res.addOperand(Inst.getOperand(1)); + Res.addOperand(Inst.getOperand(2)); + break; + case CSKY::JBR16: + Res.setOpcode(CSKY::JBR32); + Res.addOperand(Inst.getOperand(0)); + Res.addOperand(Inst.getOperand(1)); + break; + case CSKY::JBT16: + case CSKY::JBF16: + // ck801 + unsigned opcode; + if (STI.getFeatureBits()[CSKY::HasE2]) + opcode = Inst.getOpcode() == CSKY::JBT16 ? CSKY::JBT32 : CSKY::JBF32; + else + opcode = Inst.getOpcode() == CSKY::JBT16 ? CSKY::JBT_E : CSKY::JBF_E; + + Res.setOpcode(opcode); + Res.addOperand(Inst.getOperand(0)); + Res.addOperand(Inst.getOperand(1)); + Res.addOperand(Inst.getOperand(2)); + break; + } + Inst = std::move(Res); +} + +bool CSKYAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count, + const MCSubtargetInfo *STI) const { + OS.write_zeros(Count); + return true; +} + +MCAsmBackend *llvm::createCSKYAsmBackend(const Target &T, + const MCSubtargetInfo &STI, + const MCRegisterInfo &MRI, + const MCTargetOptions &Options) { + return new CSKYAsmBackend(STI, Options); +} |
