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