10b57cec5SDimitry Andric //===-- LanaiAsmBackend.cpp - Lanai Assembler Backend ---------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric
90b57cec5SDimitry Andric #include "LanaiFixupKinds.h"
100b57cec5SDimitry Andric #include "MCTargetDesc/LanaiMCTargetDesc.h"
110b57cec5SDimitry Andric #include "llvm/MC/MCAsmBackend.h"
120b57cec5SDimitry Andric #include "llvm/MC/MCAssembler.h"
130b57cec5SDimitry Andric #include "llvm/MC/MCDirectives.h"
140b57cec5SDimitry Andric #include "llvm/MC/MCELFObjectWriter.h"
150b57cec5SDimitry Andric #include "llvm/MC/MCFixupKindInfo.h"
160b57cec5SDimitry Andric #include "llvm/MC/MCObjectWriter.h"
170b57cec5SDimitry Andric #include "llvm/MC/MCSubtargetInfo.h"
180b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
190b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
200b57cec5SDimitry Andric
210b57cec5SDimitry Andric using namespace llvm;
220b57cec5SDimitry Andric
230b57cec5SDimitry Andric // Prepare value for the target space
adjustFixupValue(unsigned Kind,uint64_t Value)240b57cec5SDimitry Andric static unsigned adjustFixupValue(unsigned Kind, uint64_t Value) {
250b57cec5SDimitry Andric switch (Kind) {
260b57cec5SDimitry Andric case FK_Data_1:
270b57cec5SDimitry Andric case FK_Data_2:
280b57cec5SDimitry Andric case FK_Data_4:
290b57cec5SDimitry Andric case FK_Data_8:
300b57cec5SDimitry Andric return Value;
310b57cec5SDimitry Andric case Lanai::FIXUP_LANAI_21:
320b57cec5SDimitry Andric case Lanai::FIXUP_LANAI_21_F:
330b57cec5SDimitry Andric case Lanai::FIXUP_LANAI_25:
340b57cec5SDimitry Andric case Lanai::FIXUP_LANAI_32:
350b57cec5SDimitry Andric case Lanai::FIXUP_LANAI_HI16:
360b57cec5SDimitry Andric case Lanai::FIXUP_LANAI_LO16:
370b57cec5SDimitry Andric return Value;
380b57cec5SDimitry Andric default:
390b57cec5SDimitry Andric llvm_unreachable("Unknown fixup kind!");
400b57cec5SDimitry Andric }
410b57cec5SDimitry Andric }
420b57cec5SDimitry Andric
430b57cec5SDimitry Andric namespace {
440b57cec5SDimitry Andric class LanaiAsmBackend : public MCAsmBackend {
450b57cec5SDimitry Andric Triple::OSType OSType;
460b57cec5SDimitry Andric
470b57cec5SDimitry Andric public:
LanaiAsmBackend(const Target & T,Triple::OSType OST)480b57cec5SDimitry Andric LanaiAsmBackend(const Target &T, Triple::OSType OST)
49*5f757f3fSDimitry Andric : MCAsmBackend(llvm::endianness::big), OSType(OST) {}
500b57cec5SDimitry Andric
510b57cec5SDimitry Andric void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
520b57cec5SDimitry Andric const MCValue &Target, MutableArrayRef<char> Data,
530b57cec5SDimitry Andric uint64_t Value, bool IsResolved,
540b57cec5SDimitry Andric const MCSubtargetInfo *STI) const override;
550b57cec5SDimitry Andric
560b57cec5SDimitry Andric std::unique_ptr<MCObjectTargetWriter>
570b57cec5SDimitry Andric createObjectTargetWriter() const override;
580b57cec5SDimitry Andric
590b57cec5SDimitry Andric const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override;
600b57cec5SDimitry Andric
getNumFixupKinds() const610b57cec5SDimitry Andric unsigned getNumFixupKinds() const override {
620b57cec5SDimitry Andric return Lanai::NumTargetFixupKinds;
630b57cec5SDimitry Andric }
640b57cec5SDimitry Andric
65349cc55cSDimitry Andric bool writeNopData(raw_ostream &OS, uint64_t Count,
66349cc55cSDimitry Andric const MCSubtargetInfo *STI) const override;
670b57cec5SDimitry Andric };
680b57cec5SDimitry Andric
writeNopData(raw_ostream & OS,uint64_t Count,const MCSubtargetInfo * STI) const69349cc55cSDimitry Andric bool LanaiAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count,
70349cc55cSDimitry Andric const MCSubtargetInfo *STI) const {
710b57cec5SDimitry Andric if ((Count % 4) != 0)
720b57cec5SDimitry Andric return false;
730b57cec5SDimitry Andric
740b57cec5SDimitry Andric for (uint64_t i = 0; i < Count; i += 4)
750b57cec5SDimitry Andric OS.write("\x15\0\0\0", 4);
760b57cec5SDimitry Andric
770b57cec5SDimitry Andric return true;
780b57cec5SDimitry Andric }
790b57cec5SDimitry Andric
applyFixup(const MCAssembler & Asm,const MCFixup & Fixup,const MCValue & Target,MutableArrayRef<char> Data,uint64_t Value,bool,const MCSubtargetInfo *) const800b57cec5SDimitry Andric void LanaiAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
810b57cec5SDimitry Andric const MCValue &Target,
820b57cec5SDimitry Andric MutableArrayRef<char> Data, uint64_t Value,
830b57cec5SDimitry Andric bool /*IsResolved*/,
840b57cec5SDimitry Andric const MCSubtargetInfo * /*STI*/) const {
850b57cec5SDimitry Andric MCFixupKind Kind = Fixup.getKind();
860b57cec5SDimitry Andric Value = adjustFixupValue(static_cast<unsigned>(Kind), Value);
870b57cec5SDimitry Andric
880b57cec5SDimitry Andric if (!Value)
890b57cec5SDimitry Andric return; // This value doesn't change the encoding
900b57cec5SDimitry Andric
910b57cec5SDimitry Andric // Where in the object and where the number of bytes that need
920b57cec5SDimitry Andric // fixing up
930b57cec5SDimitry Andric unsigned Offset = Fixup.getOffset();
940b57cec5SDimitry Andric unsigned NumBytes = (getFixupKindInfo(Kind).TargetSize + 7) / 8;
950b57cec5SDimitry Andric unsigned FullSize = 4;
960b57cec5SDimitry Andric
970b57cec5SDimitry Andric // Grab current value, if any, from bits.
980b57cec5SDimitry Andric uint64_t CurVal = 0;
990b57cec5SDimitry Andric
1000b57cec5SDimitry Andric // Load instruction and apply value
1010b57cec5SDimitry Andric for (unsigned i = 0; i != NumBytes; ++i) {
1020b57cec5SDimitry Andric unsigned Idx = (FullSize - 1 - i);
1030b57cec5SDimitry Andric CurVal |= static_cast<uint64_t>(static_cast<uint8_t>(Data[Offset + Idx]))
1040b57cec5SDimitry Andric << (i * 8);
1050b57cec5SDimitry Andric }
1060b57cec5SDimitry Andric
1070b57cec5SDimitry Andric uint64_t Mask =
1080b57cec5SDimitry Andric (static_cast<uint64_t>(-1) >> (64 - getFixupKindInfo(Kind).TargetSize));
1090b57cec5SDimitry Andric CurVal |= Value & Mask;
1100b57cec5SDimitry Andric
1110b57cec5SDimitry Andric // Write out the fixed up bytes back to the code/data bits.
1120b57cec5SDimitry Andric for (unsigned i = 0; i != NumBytes; ++i) {
1130b57cec5SDimitry Andric unsigned Idx = (FullSize - 1 - i);
1140b57cec5SDimitry Andric Data[Offset + Idx] = static_cast<uint8_t>((CurVal >> (i * 8)) & 0xff);
1150b57cec5SDimitry Andric }
1160b57cec5SDimitry Andric }
1170b57cec5SDimitry Andric
1180b57cec5SDimitry Andric std::unique_ptr<MCObjectTargetWriter>
createObjectTargetWriter() const1190b57cec5SDimitry Andric LanaiAsmBackend::createObjectTargetWriter() const {
1200b57cec5SDimitry Andric return createLanaiELFObjectWriter(MCELFObjectTargetWriter::getOSABI(OSType));
1210b57cec5SDimitry Andric }
1220b57cec5SDimitry Andric
1230b57cec5SDimitry Andric const MCFixupKindInfo &
getFixupKindInfo(MCFixupKind Kind) const1240b57cec5SDimitry Andric LanaiAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {
1250b57cec5SDimitry Andric static const MCFixupKindInfo Infos[Lanai::NumTargetFixupKinds] = {
1260b57cec5SDimitry Andric // This table *must* be in same the order of fixup_* kinds in
1270b57cec5SDimitry Andric // LanaiFixupKinds.h.
1280b57cec5SDimitry Andric // Note: The number of bits indicated here are assumed to be contiguous.
1290b57cec5SDimitry Andric // This does not hold true for LANAI_21 and LANAI_21_F which are applied
1300b57cec5SDimitry Andric // to bits 0x7cffff and 0x7cfffc, respectively. Since the 'bits' counts
1310b57cec5SDimitry Andric // here are used only for cosmetic purposes, we set the size to 16 bits
1320b57cec5SDimitry Andric // for these 21-bit relocation as llvm/lib/MC/MCAsmStreamer.cpp checks
1330b57cec5SDimitry Andric // no bits are set in the fixup range.
1340b57cec5SDimitry Andric //
1350b57cec5SDimitry Andric // name offset bits flags
1360b57cec5SDimitry Andric {"FIXUP_LANAI_NONE", 0, 32, 0},
1370b57cec5SDimitry Andric {"FIXUP_LANAI_21", 16, 16 /*21*/, 0},
1380b57cec5SDimitry Andric {"FIXUP_LANAI_21_F", 16, 16 /*21*/, 0},
1390b57cec5SDimitry Andric {"FIXUP_LANAI_25", 7, 25, 0},
1400b57cec5SDimitry Andric {"FIXUP_LANAI_32", 0, 32, 0},
1410b57cec5SDimitry Andric {"FIXUP_LANAI_HI16", 16, 16, 0},
1420b57cec5SDimitry Andric {"FIXUP_LANAI_LO16", 16, 16, 0}};
1430b57cec5SDimitry Andric
1440b57cec5SDimitry Andric if (Kind < FirstTargetFixupKind)
1450b57cec5SDimitry Andric return MCAsmBackend::getFixupKindInfo(Kind);
1460b57cec5SDimitry Andric
1470b57cec5SDimitry Andric assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() &&
1480b57cec5SDimitry Andric "Invalid kind!");
1490b57cec5SDimitry Andric return Infos[Kind - FirstTargetFixupKind];
1500b57cec5SDimitry Andric }
1510b57cec5SDimitry Andric
1520b57cec5SDimitry Andric } // namespace
1530b57cec5SDimitry Andric
createLanaiAsmBackend(const Target & T,const MCSubtargetInfo & STI,const MCRegisterInfo &,const MCTargetOptions &)1540b57cec5SDimitry Andric MCAsmBackend *llvm::createLanaiAsmBackend(const Target &T,
1550b57cec5SDimitry Andric const MCSubtargetInfo &STI,
1560b57cec5SDimitry Andric const MCRegisterInfo & /*MRI*/,
1570b57cec5SDimitry Andric const MCTargetOptions & /*Options*/) {
1580b57cec5SDimitry Andric const Triple &TT = STI.getTargetTriple();
1590b57cec5SDimitry Andric if (!TT.isOSBinFormatELF())
1600b57cec5SDimitry Andric llvm_unreachable("OS not supported");
1610b57cec5SDimitry Andric
1620b57cec5SDimitry Andric return new LanaiAsmBackend(T, TT.getOS());
1630b57cec5SDimitry Andric }
164