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(support::little), OSABI(osABI), IsLittleEndian(isLE) {} 34 35 unsigned getNumFixupKinds() const override { 36 return Xtensa::NumTargetFixupKinds; 37 } 38 const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override; 39 void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, 40 const MCValue &Target, MutableArrayRef<char> Data, 41 uint64_t Value, bool IsResolved, 42 const MCSubtargetInfo *STI) const override; 43 bool mayNeedRelaxation(const MCInst &Inst, 44 const MCSubtargetInfo &STI) const override; 45 bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value, 46 const MCRelaxableFragment *Fragment, 47 const MCAsmLayout &Layout) const override; 48 void relaxInstruction(MCInst &Inst, 49 const MCSubtargetInfo &STI) const override; 50 bool writeNopData(raw_ostream &OS, uint64_t Count, 51 const MCSubtargetInfo *STI) const override; 52 53 std::unique_ptr<MCObjectTargetWriter> createObjectTargetWriter() const override { 54 return createXtensaObjectWriter(OSABI, IsLittleEndian); 55 } 56 }; 57 } // namespace llvm 58 59 const MCFixupKindInfo & 60 XtensaMCAsmBackend::getFixupKindInfo(MCFixupKind Kind) const { 61 const static MCFixupKindInfo Infos[Xtensa::NumTargetFixupKinds] = { 62 // name offset bits flags 63 {"fixup_xtensa_branch_6", 0, 16, MCFixupKindInfo::FKF_IsPCRel}, 64 {"fixup_xtensa_branch_8", 16, 8, MCFixupKindInfo::FKF_IsPCRel}, 65 {"fixup_xtensa_branch_12", 12, 12, MCFixupKindInfo::FKF_IsPCRel}, 66 {"fixup_xtensa_jump_18", 6, 18, MCFixupKindInfo::FKF_IsPCRel}, 67 {"fixup_xtensa_call_18", 6, 18, 68 MCFixupKindInfo::FKF_IsPCRel | 69 MCFixupKindInfo::FKF_IsAlignedDownTo32Bits}, 70 {"fixup_xtensa_l32r_16", 8, 16, 71 MCFixupKindInfo::FKF_IsPCRel | 72 MCFixupKindInfo::FKF_IsAlignedDownTo32Bits}}; 73 74 if (Kind < FirstTargetFixupKind) 75 return MCAsmBackend::getFixupKindInfo(Kind); 76 assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() && 77 "Invalid kind!"); 78 return Infos[Kind - FirstTargetFixupKind]; 79 } 80 81 static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value, 82 MCContext &Ctx) { 83 unsigned Kind = Fixup.getKind(); 84 switch (Kind) { 85 default: 86 llvm_unreachable("Unknown fixup kind!"); 87 case FK_Data_1: 88 case FK_Data_2: 89 case FK_Data_4: 90 case FK_Data_8: 91 return Value; 92 case Xtensa::fixup_xtensa_branch_6: { 93 Value -= 4; 94 if (!isInt<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 bool XtensaMCAsmBackend::fixupNeedsRelaxation( 175 const MCFixup &Fixup, uint64_t Value, const MCRelaxableFragment *Fragment, 176 const MCAsmLayout &Layout) const { 177 return false; 178 } 179 180 void XtensaMCAsmBackend::relaxInstruction(MCInst &Inst, 181 const MCSubtargetInfo &STI) const {} 182 183 bool XtensaMCAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count, 184 const MCSubtargetInfo *STI) const { 185 uint64_t NumNops24b = Count / 3; 186 187 for (uint64_t i = 0; i != NumNops24b; ++i) { 188 // Currently just little-endian machine supported, 189 // but probably big-endian will be also implemented in future 190 if (IsLittleEndian) { 191 OS.write("\xf0", 1); 192 OS.write("\x20", 1); 193 OS.write("\0x00", 1); 194 } else { 195 report_fatal_error("Big-endian mode currently is not supported!"); 196 } 197 Count -= 3; 198 } 199 200 // TODO maybe function should return error if (Count > 0) 201 switch (Count) { 202 default: 203 break; 204 case 1: 205 OS.write("\0", 1); 206 break; 207 case 2: 208 // NOP.N instruction 209 OS.write("\x3d", 1); 210 OS.write("\xf0", 1); 211 break; 212 } 213 214 return true; 215 } 216 217 MCAsmBackend *llvm::createXtensaMCAsmBackend(const Target &T, 218 const MCSubtargetInfo &STI, 219 const MCRegisterInfo &MRI, 220 const MCTargetOptions &Options) { 221 uint8_t OSABI = 222 MCELFObjectTargetWriter::getOSABI(STI.getTargetTriple().getOS()); 223 return new llvm::XtensaMCAsmBackend(OSABI, true); 224 } 225