160172097SAndrei Safronov //===-- XtensaMCAsmBackend.cpp - Xtensa assembler backend -----------------===// 260172097SAndrei Safronov // 360172097SAndrei Safronov // The LLVM Compiler Infrastructure 460172097SAndrei Safronov // 560172097SAndrei Safronov // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 660172097SAndrei Safronov // See https://llvm.org/LICENSE.txt for license information. 760172097SAndrei Safronov // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 860172097SAndrei Safronov // 960172097SAndrei Safronov //===----------------------------------------------------------------------===// 1060172097SAndrei Safronov 11ff25800dSAndrei Safronov #include "MCTargetDesc/XtensaFixupKinds.h" 1260172097SAndrei Safronov #include "MCTargetDesc/XtensaMCTargetDesc.h" 1360172097SAndrei Safronov #include "llvm/MC/MCAsmBackend.h" 1460172097SAndrei Safronov #include "llvm/MC/MCAssembler.h" 1560172097SAndrei Safronov #include "llvm/MC/MCContext.h" 1660172097SAndrei Safronov #include "llvm/MC/MCELFObjectWriter.h" 1760172097SAndrei Safronov #include "llvm/MC/MCFixupKindInfo.h" 1860172097SAndrei Safronov #include "llvm/MC/MCInst.h" 1960172097SAndrei Safronov #include "llvm/MC/MCObjectWriter.h" 2060172097SAndrei Safronov #include "llvm/MC/MCSubtargetInfo.h" 2160172097SAndrei Safronov #include "llvm/Support/raw_ostream.h" 2260172097SAndrei Safronov 2360172097SAndrei Safronov using namespace llvm; 2460172097SAndrei Safronov 2560172097SAndrei Safronov namespace llvm { 2660172097SAndrei Safronov class MCObjectTargetWriter; 2760172097SAndrei Safronov class XtensaMCAsmBackend : public MCAsmBackend { 2860172097SAndrei Safronov uint8_t OSABI; 2960172097SAndrei Safronov bool IsLittleEndian; 3060172097SAndrei Safronov 3160172097SAndrei Safronov public: 3260172097SAndrei Safronov XtensaMCAsmBackend(uint8_t osABI, bool isLE) 334a0ccfa8SKazu Hirata : MCAsmBackend(llvm::endianness::little), OSABI(osABI), 344a0ccfa8SKazu Hirata IsLittleEndian(isLE) {} 3560172097SAndrei Safronov 36ff25800dSAndrei Safronov unsigned getNumFixupKinds() const override { 37ff25800dSAndrei Safronov return Xtensa::NumTargetFixupKinds; 38ff25800dSAndrei Safronov } 3960172097SAndrei Safronov const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override; 4060172097SAndrei Safronov void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, 4160172097SAndrei Safronov const MCValue &Target, MutableArrayRef<char> Data, 4260172097SAndrei Safronov uint64_t Value, bool IsResolved, 4360172097SAndrei Safronov const MCSubtargetInfo *STI) const override; 4460172097SAndrei Safronov bool mayNeedRelaxation(const MCInst &Inst, 4560172097SAndrei Safronov const MCSubtargetInfo &STI) const override; 4660172097SAndrei Safronov void relaxInstruction(MCInst &Inst, 4760172097SAndrei Safronov const MCSubtargetInfo &STI) const override; 4860172097SAndrei Safronov bool writeNopData(raw_ostream &OS, uint64_t Count, 4960172097SAndrei Safronov const MCSubtargetInfo *STI) const override; 5060172097SAndrei Safronov 5160172097SAndrei Safronov std::unique_ptr<MCObjectTargetWriter> createObjectTargetWriter() const override { 5260172097SAndrei Safronov return createXtensaObjectWriter(OSABI, IsLittleEndian); 5360172097SAndrei Safronov } 5460172097SAndrei Safronov }; 5560172097SAndrei Safronov } // namespace llvm 5660172097SAndrei Safronov 5760172097SAndrei Safronov const MCFixupKindInfo & 5860172097SAndrei Safronov XtensaMCAsmBackend::getFixupKindInfo(MCFixupKind Kind) const { 59ff25800dSAndrei Safronov const static MCFixupKindInfo Infos[Xtensa::NumTargetFixupKinds] = { 60ff25800dSAndrei Safronov // name offset bits flags 61ff25800dSAndrei Safronov {"fixup_xtensa_branch_6", 0, 16, MCFixupKindInfo::FKF_IsPCRel}, 62ff25800dSAndrei Safronov {"fixup_xtensa_branch_8", 16, 8, MCFixupKindInfo::FKF_IsPCRel}, 63ff25800dSAndrei Safronov {"fixup_xtensa_branch_12", 12, 12, MCFixupKindInfo::FKF_IsPCRel}, 64ff25800dSAndrei Safronov {"fixup_xtensa_jump_18", 6, 18, MCFixupKindInfo::FKF_IsPCRel}, 65ff25800dSAndrei Safronov {"fixup_xtensa_call_18", 6, 18, 66ff25800dSAndrei Safronov MCFixupKindInfo::FKF_IsPCRel | 67ff25800dSAndrei Safronov MCFixupKindInfo::FKF_IsAlignedDownTo32Bits}, 68ff25800dSAndrei Safronov {"fixup_xtensa_l32r_16", 8, 16, 69ff25800dSAndrei Safronov MCFixupKindInfo::FKF_IsPCRel | 70ff25800dSAndrei Safronov MCFixupKindInfo::FKF_IsAlignedDownTo32Bits}}; 71ff25800dSAndrei Safronov 72ff25800dSAndrei Safronov if (Kind < FirstTargetFixupKind) 73ff25800dSAndrei Safronov return MCAsmBackend::getFixupKindInfo(Kind); 74ff25800dSAndrei Safronov assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() && 75ff25800dSAndrei Safronov "Invalid kind!"); 76ff25800dSAndrei Safronov return Infos[Kind - FirstTargetFixupKind]; 7760172097SAndrei Safronov } 78ff25800dSAndrei Safronov 79ff25800dSAndrei Safronov static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value, 80ff25800dSAndrei Safronov MCContext &Ctx) { 81ff25800dSAndrei Safronov unsigned Kind = Fixup.getKind(); 82ff25800dSAndrei Safronov switch (Kind) { 83ff25800dSAndrei Safronov default: 84ff25800dSAndrei Safronov llvm_unreachable("Unknown fixup kind!"); 85ff25800dSAndrei Safronov case FK_Data_1: 86ff25800dSAndrei Safronov case FK_Data_2: 87ff25800dSAndrei Safronov case FK_Data_4: 88ff25800dSAndrei Safronov case FK_Data_8: 89ff25800dSAndrei Safronov return Value; 90ff25800dSAndrei Safronov case Xtensa::fixup_xtensa_branch_6: { 91*c6967efeSAndrei Safronov if (!Value) 92*c6967efeSAndrei Safronov return 0; 93ff25800dSAndrei Safronov Value -= 4; 94*c6967efeSAndrei Safronov if (!isUInt<6>(Value)) 95ff25800dSAndrei Safronov Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); 96ff25800dSAndrei Safronov unsigned Hi2 = (Value >> 4) & 0x3; 97ff25800dSAndrei Safronov unsigned Lo4 = Value & 0xf; 98ff25800dSAndrei Safronov return (Hi2 << 4) | (Lo4 << 12); 99ff25800dSAndrei Safronov } 100ff25800dSAndrei Safronov case Xtensa::fixup_xtensa_branch_8: 101ff25800dSAndrei Safronov Value -= 4; 102ff25800dSAndrei Safronov if (!isInt<8>(Value)) 103ff25800dSAndrei Safronov Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); 104ff25800dSAndrei Safronov return (Value & 0xff); 105ff25800dSAndrei Safronov case Xtensa::fixup_xtensa_branch_12: 106ff25800dSAndrei Safronov Value -= 4; 107ff25800dSAndrei Safronov if (!isInt<12>(Value)) 108ff25800dSAndrei Safronov Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); 109ff25800dSAndrei Safronov return (Value & 0xfff); 110ff25800dSAndrei Safronov case Xtensa::fixup_xtensa_jump_18: 111ff25800dSAndrei Safronov Value -= 4; 112ff25800dSAndrei Safronov if (!isInt<18>(Value)) 113ff25800dSAndrei Safronov Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); 114ff25800dSAndrei Safronov return (Value & 0x3ffff); 115ff25800dSAndrei Safronov case Xtensa::fixup_xtensa_call_18: 116ff25800dSAndrei Safronov Value -= 4; 117ff25800dSAndrei Safronov if (!isInt<20>(Value)) 118ff25800dSAndrei Safronov Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); 119ff25800dSAndrei Safronov if (Value & 0x3) 120ff25800dSAndrei Safronov Ctx.reportError(Fixup.getLoc(), "fixup value must be 4-byte aligned"); 121ff25800dSAndrei Safronov return (Value & 0xffffc) >> 2; 122ff25800dSAndrei Safronov case Xtensa::fixup_xtensa_l32r_16: 123ff25800dSAndrei Safronov unsigned Offset = Fixup.getOffset(); 124ff25800dSAndrei Safronov if (Offset & 0x3) 125ff25800dSAndrei Safronov Value -= 4; 126ff25800dSAndrei Safronov if (!isInt<18>(Value) && (Value & 0x20000)) 127ff25800dSAndrei Safronov Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); 128ff25800dSAndrei Safronov if (Value & 0x3) 129ff25800dSAndrei Safronov Ctx.reportError(Fixup.getLoc(), "fixup value must be 4-byte aligned"); 130ff25800dSAndrei Safronov return (Value & 0x3fffc) >> 2; 131ff25800dSAndrei Safronov } 132ff25800dSAndrei Safronov } 133ff25800dSAndrei Safronov 134ff25800dSAndrei Safronov static unsigned getSize(unsigned Kind) { 135ff25800dSAndrei Safronov switch (Kind) { 136ff25800dSAndrei Safronov default: 137ff25800dSAndrei Safronov return 3; 138ff25800dSAndrei Safronov case MCFixupKind::FK_Data_4: 139ff25800dSAndrei Safronov return 4; 140ff25800dSAndrei Safronov case Xtensa::fixup_xtensa_branch_6: 141ff25800dSAndrei Safronov return 2; 142ff25800dSAndrei Safronov } 143ff25800dSAndrei Safronov } 144ff25800dSAndrei Safronov 14560172097SAndrei Safronov void XtensaMCAsmBackend::applyFixup(const MCAssembler &Asm, 14660172097SAndrei Safronov const MCFixup &Fixup, const MCValue &Target, 14760172097SAndrei Safronov MutableArrayRef<char> Data, uint64_t Value, 14860172097SAndrei Safronov bool IsResolved, 149ff25800dSAndrei Safronov const MCSubtargetInfo *STI) const { 150ff25800dSAndrei Safronov MCContext &Ctx = Asm.getContext(); 151ff25800dSAndrei Safronov MCFixupKindInfo Info = getFixupKindInfo(Fixup.getKind()); 152ff25800dSAndrei Safronov 153ff25800dSAndrei Safronov Value = adjustFixupValue(Fixup, Value, Ctx); 154ff25800dSAndrei Safronov 155ff25800dSAndrei Safronov // Shift the value into position. 156ff25800dSAndrei Safronov Value <<= Info.TargetOffset; 157ff25800dSAndrei Safronov 158ff25800dSAndrei Safronov if (!Value) 159ff25800dSAndrei Safronov return; // Doesn't change encoding. 160ff25800dSAndrei Safronov 161ff25800dSAndrei Safronov unsigned Offset = Fixup.getOffset(); 162ff25800dSAndrei Safronov unsigned FullSize = getSize(Fixup.getKind()); 163ff25800dSAndrei Safronov 164ff25800dSAndrei Safronov for (unsigned i = 0; i != FullSize; ++i) { 165ff25800dSAndrei Safronov Data[Offset + i] |= uint8_t((Value >> (i * 8)) & 0xff); 166ff25800dSAndrei Safronov } 167ff25800dSAndrei Safronov } 16860172097SAndrei Safronov 16960172097SAndrei Safronov bool XtensaMCAsmBackend::mayNeedRelaxation(const MCInst &Inst, 17060172097SAndrei Safronov const MCSubtargetInfo &STI) const { 17160172097SAndrei Safronov return false; 17260172097SAndrei Safronov } 17360172097SAndrei Safronov 17460172097SAndrei Safronov void XtensaMCAsmBackend::relaxInstruction(MCInst &Inst, 17560172097SAndrei Safronov const MCSubtargetInfo &STI) const {} 17660172097SAndrei Safronov 17760172097SAndrei Safronov bool XtensaMCAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count, 17860172097SAndrei Safronov const MCSubtargetInfo *STI) const { 17960172097SAndrei Safronov uint64_t NumNops24b = Count / 3; 18060172097SAndrei Safronov 18160172097SAndrei Safronov for (uint64_t i = 0; i != NumNops24b; ++i) { 18260172097SAndrei Safronov // Currently just little-endian machine supported, 18360172097SAndrei Safronov // but probably big-endian will be also implemented in future 18460172097SAndrei Safronov if (IsLittleEndian) { 18560172097SAndrei Safronov OS.write("\xf0", 1); 18660172097SAndrei Safronov OS.write("\x20", 1); 18760172097SAndrei Safronov OS.write("\0x00", 1); 18860172097SAndrei Safronov } else { 18960172097SAndrei Safronov report_fatal_error("Big-endian mode currently is not supported!"); 19060172097SAndrei Safronov } 19160172097SAndrei Safronov Count -= 3; 19260172097SAndrei Safronov } 19360172097SAndrei Safronov 19460172097SAndrei Safronov // TODO maybe function should return error if (Count > 0) 19560172097SAndrei Safronov switch (Count) { 19660172097SAndrei Safronov default: 19760172097SAndrei Safronov break; 19860172097SAndrei Safronov case 1: 19960172097SAndrei Safronov OS.write("\0", 1); 20060172097SAndrei Safronov break; 20160172097SAndrei Safronov case 2: 20260172097SAndrei Safronov // NOP.N instruction 20360172097SAndrei Safronov OS.write("\x3d", 1); 20460172097SAndrei Safronov OS.write("\xf0", 1); 20560172097SAndrei Safronov break; 20660172097SAndrei Safronov } 20760172097SAndrei Safronov 20860172097SAndrei Safronov return true; 20960172097SAndrei Safronov } 21060172097SAndrei Safronov 21160172097SAndrei Safronov MCAsmBackend *llvm::createXtensaMCAsmBackend(const Target &T, 21260172097SAndrei Safronov const MCSubtargetInfo &STI, 21360172097SAndrei Safronov const MCRegisterInfo &MRI, 21460172097SAndrei Safronov const MCTargetOptions &Options) { 21560172097SAndrei Safronov uint8_t OSABI = 21660172097SAndrei Safronov MCELFObjectTargetWriter::getOSABI(STI.getTargetTriple().getOS()); 21760172097SAndrei Safronov return new llvm::XtensaMCAsmBackend(OSABI, true); 21860172097SAndrei Safronov } 219