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