1bdd1243dSDimitry Andric //===-- XtensaMCAsmBackend.cpp - Xtensa assembler backend -----------------===// 2bdd1243dSDimitry Andric // 3bdd1243dSDimitry Andric // The LLVM Compiler Infrastructure 4bdd1243dSDimitry Andric // 5bdd1243dSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 6bdd1243dSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 7bdd1243dSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 8bdd1243dSDimitry Andric // 9bdd1243dSDimitry Andric //===----------------------------------------------------------------------===// 10bdd1243dSDimitry Andric 11bdd1243dSDimitry Andric #include "MCTargetDesc/XtensaFixupKinds.h" 12bdd1243dSDimitry Andric #include "MCTargetDesc/XtensaMCTargetDesc.h" 13bdd1243dSDimitry Andric #include "llvm/MC/MCAsmBackend.h" 14bdd1243dSDimitry Andric #include "llvm/MC/MCAssembler.h" 15bdd1243dSDimitry Andric #include "llvm/MC/MCContext.h" 16bdd1243dSDimitry Andric #include "llvm/MC/MCELFObjectWriter.h" 17bdd1243dSDimitry Andric #include "llvm/MC/MCFixupKindInfo.h" 18bdd1243dSDimitry Andric #include "llvm/MC/MCInst.h" 19bdd1243dSDimitry Andric #include "llvm/MC/MCObjectWriter.h" 20bdd1243dSDimitry Andric #include "llvm/MC/MCSubtargetInfo.h" 21bdd1243dSDimitry Andric #include "llvm/Support/raw_ostream.h" 22bdd1243dSDimitry Andric 23bdd1243dSDimitry Andric using namespace llvm; 24bdd1243dSDimitry Andric 25bdd1243dSDimitry Andric namespace llvm { 26bdd1243dSDimitry Andric class MCObjectTargetWriter; 27bdd1243dSDimitry Andric class XtensaMCAsmBackend : public MCAsmBackend { 28bdd1243dSDimitry Andric uint8_t OSABI; 29bdd1243dSDimitry Andric bool IsLittleEndian; 30bdd1243dSDimitry Andric 31bdd1243dSDimitry Andric public: 32bdd1243dSDimitry Andric XtensaMCAsmBackend(uint8_t osABI, bool isLE) 33*5f757f3fSDimitry Andric : MCAsmBackend(llvm::endianness::little), OSABI(osABI), 34*5f757f3fSDimitry Andric IsLittleEndian(isLE) {} 35bdd1243dSDimitry Andric 36bdd1243dSDimitry Andric unsigned getNumFixupKinds() const override { 37bdd1243dSDimitry Andric return Xtensa::NumTargetFixupKinds; 38bdd1243dSDimitry Andric } 39bdd1243dSDimitry Andric const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override; 40bdd1243dSDimitry Andric void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, 41bdd1243dSDimitry Andric const MCValue &Target, MutableArrayRef<char> Data, 42bdd1243dSDimitry Andric uint64_t Value, bool IsResolved, 43bdd1243dSDimitry Andric const MCSubtargetInfo *STI) const override; 44bdd1243dSDimitry Andric bool mayNeedRelaxation(const MCInst &Inst, 45bdd1243dSDimitry Andric const MCSubtargetInfo &STI) const override; 46bdd1243dSDimitry Andric void relaxInstruction(MCInst &Inst, 47bdd1243dSDimitry Andric const MCSubtargetInfo &STI) const override; 48bdd1243dSDimitry Andric bool writeNopData(raw_ostream &OS, uint64_t Count, 49bdd1243dSDimitry Andric const MCSubtargetInfo *STI) const override; 50bdd1243dSDimitry Andric 51bdd1243dSDimitry Andric std::unique_ptr<MCObjectTargetWriter> createObjectTargetWriter() const override { 52bdd1243dSDimitry Andric return createXtensaObjectWriter(OSABI, IsLittleEndian); 53bdd1243dSDimitry Andric } 54bdd1243dSDimitry Andric }; 55bdd1243dSDimitry Andric } // namespace llvm 56bdd1243dSDimitry Andric 57bdd1243dSDimitry Andric const MCFixupKindInfo & 58bdd1243dSDimitry Andric XtensaMCAsmBackend::getFixupKindInfo(MCFixupKind Kind) const { 59bdd1243dSDimitry Andric const static MCFixupKindInfo Infos[Xtensa::NumTargetFixupKinds] = { 60bdd1243dSDimitry Andric // name offset bits flags 61bdd1243dSDimitry Andric {"fixup_xtensa_branch_6", 0, 16, MCFixupKindInfo::FKF_IsPCRel}, 62bdd1243dSDimitry Andric {"fixup_xtensa_branch_8", 16, 8, MCFixupKindInfo::FKF_IsPCRel}, 63bdd1243dSDimitry Andric {"fixup_xtensa_branch_12", 12, 12, MCFixupKindInfo::FKF_IsPCRel}, 64bdd1243dSDimitry Andric {"fixup_xtensa_jump_18", 6, 18, MCFixupKindInfo::FKF_IsPCRel}, 65bdd1243dSDimitry Andric {"fixup_xtensa_call_18", 6, 18, 66bdd1243dSDimitry Andric MCFixupKindInfo::FKF_IsPCRel | 67bdd1243dSDimitry Andric MCFixupKindInfo::FKF_IsAlignedDownTo32Bits}, 68bdd1243dSDimitry Andric {"fixup_xtensa_l32r_16", 8, 16, 69bdd1243dSDimitry Andric MCFixupKindInfo::FKF_IsPCRel | 70bdd1243dSDimitry Andric MCFixupKindInfo::FKF_IsAlignedDownTo32Bits}}; 71bdd1243dSDimitry Andric 72bdd1243dSDimitry Andric if (Kind < FirstTargetFixupKind) 73bdd1243dSDimitry Andric return MCAsmBackend::getFixupKindInfo(Kind); 74bdd1243dSDimitry Andric assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() && 75bdd1243dSDimitry Andric "Invalid kind!"); 76bdd1243dSDimitry Andric return Infos[Kind - FirstTargetFixupKind]; 77bdd1243dSDimitry Andric } 78bdd1243dSDimitry Andric 79bdd1243dSDimitry Andric static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value, 80bdd1243dSDimitry Andric MCContext &Ctx) { 81bdd1243dSDimitry Andric unsigned Kind = Fixup.getKind(); 82bdd1243dSDimitry Andric switch (Kind) { 83bdd1243dSDimitry Andric default: 84bdd1243dSDimitry Andric llvm_unreachable("Unknown fixup kind!"); 85bdd1243dSDimitry Andric case FK_Data_1: 86bdd1243dSDimitry Andric case FK_Data_2: 87bdd1243dSDimitry Andric case FK_Data_4: 88bdd1243dSDimitry Andric case FK_Data_8: 89bdd1243dSDimitry Andric return Value; 90bdd1243dSDimitry Andric case Xtensa::fixup_xtensa_branch_6: { 91bdd1243dSDimitry Andric Value -= 4; 92bdd1243dSDimitry Andric if (!isInt<6>(Value)) 93bdd1243dSDimitry Andric Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); 94bdd1243dSDimitry Andric unsigned Hi2 = (Value >> 4) & 0x3; 95bdd1243dSDimitry Andric unsigned Lo4 = Value & 0xf; 96bdd1243dSDimitry Andric return (Hi2 << 4) | (Lo4 << 12); 97bdd1243dSDimitry Andric } 98bdd1243dSDimitry Andric case Xtensa::fixup_xtensa_branch_8: 99bdd1243dSDimitry Andric Value -= 4; 100bdd1243dSDimitry Andric if (!isInt<8>(Value)) 101bdd1243dSDimitry Andric Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); 102bdd1243dSDimitry Andric return (Value & 0xff); 103bdd1243dSDimitry Andric case Xtensa::fixup_xtensa_branch_12: 104bdd1243dSDimitry Andric Value -= 4; 105bdd1243dSDimitry Andric if (!isInt<12>(Value)) 106bdd1243dSDimitry Andric Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); 107bdd1243dSDimitry Andric return (Value & 0xfff); 108bdd1243dSDimitry Andric case Xtensa::fixup_xtensa_jump_18: 109bdd1243dSDimitry Andric Value -= 4; 110bdd1243dSDimitry Andric if (!isInt<18>(Value)) 111bdd1243dSDimitry Andric Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); 112bdd1243dSDimitry Andric return (Value & 0x3ffff); 113bdd1243dSDimitry Andric case Xtensa::fixup_xtensa_call_18: 114bdd1243dSDimitry Andric Value -= 4; 115bdd1243dSDimitry Andric if (!isInt<20>(Value)) 116bdd1243dSDimitry Andric Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); 117bdd1243dSDimitry Andric if (Value & 0x3) 118bdd1243dSDimitry Andric Ctx.reportError(Fixup.getLoc(), "fixup value must be 4-byte aligned"); 119bdd1243dSDimitry Andric return (Value & 0xffffc) >> 2; 120bdd1243dSDimitry Andric case Xtensa::fixup_xtensa_l32r_16: 121bdd1243dSDimitry Andric unsigned Offset = Fixup.getOffset(); 122bdd1243dSDimitry Andric if (Offset & 0x3) 123bdd1243dSDimitry Andric Value -= 4; 124bdd1243dSDimitry Andric if (!isInt<18>(Value) && (Value & 0x20000)) 125bdd1243dSDimitry Andric Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); 126bdd1243dSDimitry Andric if (Value & 0x3) 127bdd1243dSDimitry Andric Ctx.reportError(Fixup.getLoc(), "fixup value must be 4-byte aligned"); 128bdd1243dSDimitry Andric return (Value & 0x3fffc) >> 2; 129bdd1243dSDimitry Andric } 130bdd1243dSDimitry Andric } 131bdd1243dSDimitry Andric 132bdd1243dSDimitry Andric static unsigned getSize(unsigned Kind) { 133bdd1243dSDimitry Andric switch (Kind) { 134bdd1243dSDimitry Andric default: 135bdd1243dSDimitry Andric return 3; 136bdd1243dSDimitry Andric case MCFixupKind::FK_Data_4: 137bdd1243dSDimitry Andric return 4; 138bdd1243dSDimitry Andric case Xtensa::fixup_xtensa_branch_6: 139bdd1243dSDimitry Andric return 2; 140bdd1243dSDimitry Andric } 141bdd1243dSDimitry Andric } 142bdd1243dSDimitry Andric 143bdd1243dSDimitry Andric void XtensaMCAsmBackend::applyFixup(const MCAssembler &Asm, 144bdd1243dSDimitry Andric const MCFixup &Fixup, const MCValue &Target, 145bdd1243dSDimitry Andric MutableArrayRef<char> Data, uint64_t Value, 146bdd1243dSDimitry Andric bool IsResolved, 147bdd1243dSDimitry Andric const MCSubtargetInfo *STI) const { 148bdd1243dSDimitry Andric MCContext &Ctx = Asm.getContext(); 149bdd1243dSDimitry Andric MCFixupKindInfo Info = getFixupKindInfo(Fixup.getKind()); 150bdd1243dSDimitry Andric 151bdd1243dSDimitry Andric Value = adjustFixupValue(Fixup, Value, Ctx); 152bdd1243dSDimitry Andric 153bdd1243dSDimitry Andric // Shift the value into position. 154bdd1243dSDimitry Andric Value <<= Info.TargetOffset; 155bdd1243dSDimitry Andric 156bdd1243dSDimitry Andric if (!Value) 157bdd1243dSDimitry Andric return; // Doesn't change encoding. 158bdd1243dSDimitry Andric 159bdd1243dSDimitry Andric unsigned Offset = Fixup.getOffset(); 160bdd1243dSDimitry Andric unsigned FullSize = getSize(Fixup.getKind()); 161bdd1243dSDimitry Andric 162bdd1243dSDimitry Andric for (unsigned i = 0; i != FullSize; ++i) { 163bdd1243dSDimitry Andric Data[Offset + i] |= uint8_t((Value >> (i * 8)) & 0xff); 164bdd1243dSDimitry Andric } 165bdd1243dSDimitry Andric } 166bdd1243dSDimitry Andric 167bdd1243dSDimitry Andric bool XtensaMCAsmBackend::mayNeedRelaxation(const MCInst &Inst, 168bdd1243dSDimitry Andric const MCSubtargetInfo &STI) const { 169bdd1243dSDimitry Andric return false; 170bdd1243dSDimitry Andric } 171bdd1243dSDimitry Andric 172bdd1243dSDimitry Andric void XtensaMCAsmBackend::relaxInstruction(MCInst &Inst, 173bdd1243dSDimitry Andric const MCSubtargetInfo &STI) const {} 174bdd1243dSDimitry Andric 175bdd1243dSDimitry Andric bool XtensaMCAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count, 176bdd1243dSDimitry Andric const MCSubtargetInfo *STI) const { 177bdd1243dSDimitry Andric uint64_t NumNops24b = Count / 3; 178bdd1243dSDimitry Andric 179bdd1243dSDimitry Andric for (uint64_t i = 0; i != NumNops24b; ++i) { 180bdd1243dSDimitry Andric // Currently just little-endian machine supported, 181bdd1243dSDimitry Andric // but probably big-endian will be also implemented in future 182bdd1243dSDimitry Andric if (IsLittleEndian) { 183bdd1243dSDimitry Andric OS.write("\xf0", 1); 184bdd1243dSDimitry Andric OS.write("\x20", 1); 185bdd1243dSDimitry Andric OS.write("\0x00", 1); 186bdd1243dSDimitry Andric } else { 187bdd1243dSDimitry Andric report_fatal_error("Big-endian mode currently is not supported!"); 188bdd1243dSDimitry Andric } 189bdd1243dSDimitry Andric Count -= 3; 190bdd1243dSDimitry Andric } 191bdd1243dSDimitry Andric 192bdd1243dSDimitry Andric // TODO maybe function should return error if (Count > 0) 193bdd1243dSDimitry Andric switch (Count) { 194bdd1243dSDimitry Andric default: 195bdd1243dSDimitry Andric break; 196bdd1243dSDimitry Andric case 1: 197bdd1243dSDimitry Andric OS.write("\0", 1); 198bdd1243dSDimitry Andric break; 199bdd1243dSDimitry Andric case 2: 200bdd1243dSDimitry Andric // NOP.N instruction 201bdd1243dSDimitry Andric OS.write("\x3d", 1); 202bdd1243dSDimitry Andric OS.write("\xf0", 1); 203bdd1243dSDimitry Andric break; 204bdd1243dSDimitry Andric } 205bdd1243dSDimitry Andric 206bdd1243dSDimitry Andric return true; 207bdd1243dSDimitry Andric } 208bdd1243dSDimitry Andric 209bdd1243dSDimitry Andric MCAsmBackend *llvm::createXtensaMCAsmBackend(const Target &T, 210bdd1243dSDimitry Andric const MCSubtargetInfo &STI, 211bdd1243dSDimitry Andric const MCRegisterInfo &MRI, 212bdd1243dSDimitry Andric const MCTargetOptions &Options) { 213bdd1243dSDimitry Andric uint8_t OSABI = 214bdd1243dSDimitry Andric MCELFObjectTargetWriter::getOSABI(STI.getTargetTriple().getOS()); 215bdd1243dSDimitry Andric return new llvm::XtensaMCAsmBackend(OSABI, true); 216bdd1243dSDimitry Andric } 217