xref: /llvm-project/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaAsmBackend.cpp (revision c6967efe780d6cc5d70fc8cadbd227353b6768f1)
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