1//===-- VEAsmBackend.cpp - VE Assembler Backend ---------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "MCTargetDesc/VEFixupKinds.h"
10#include "MCTargetDesc/VEMCTargetDesc.h"
11#include "llvm/MC/MCAsmBackend.h"
12#include "llvm/MC/MCELFObjectWriter.h"
13#include "llvm/MC/MCExpr.h"
14#include "llvm/MC/MCFixupKindInfo.h"
15#include "llvm/MC/MCObjectWriter.h"
16#include "llvm/MC/MCSubtargetInfo.h"
17#include "llvm/MC/MCValue.h"
18#include "llvm/MC/TargetRegistry.h"
19#include "llvm/Support/EndianStream.h"
20
21using namespace llvm;
22
23static uint64_t adjustFixupValue(unsigned Kind, uint64_t Value) {
24 switch (Kind) {
25 default:
26 llvm_unreachable("Unknown fixup kind!");
27 case FK_Data_1:
28 case FK_Data_2:
29 case FK_Data_4:
30 case FK_Data_8:
31 return Value;
32 case VE::fixup_ve_hi32:
33 case VE::fixup_ve_pc_hi32:
34 case VE::fixup_ve_got_hi32:
35 case VE::fixup_ve_gotoff_hi32:
36 case VE::fixup_ve_plt_hi32:
37 case VE::fixup_ve_tls_gd_hi32:
38 case VE::fixup_ve_tpoff_hi32:
39 return (Value >> 32) & 0xffffffff;
40 case VE::fixup_ve_reflong:
41 case VE::fixup_ve_srel32:
42 case VE::fixup_ve_lo32:
43 case VE::fixup_ve_pc_lo32:
44 case VE::fixup_ve_got_lo32:
45 case VE::fixup_ve_gotoff_lo32:
46 case VE::fixup_ve_plt_lo32:
47 case VE::fixup_ve_tls_gd_lo32:
48 case VE::fixup_ve_tpoff_lo32:
49 return Value & 0xffffffff;
50 }
51}
52
53/// getFixupKindNumBytes - The number of bytes the fixup may change.
54static unsigned getFixupKindNumBytes(unsigned Kind) {
55 switch (Kind) {
56 default:
57 llvm_unreachable("Unknown fixup kind!");
58 case FK_Data_1:
59 return 1;
60 case FK_Data_2:
61 return 2;
62 return 4;
63 case FK_Data_4:
64 case VE::fixup_ve_reflong:
65 case VE::fixup_ve_srel32:
66 case VE::fixup_ve_hi32:
67 case VE::fixup_ve_lo32:
68 case VE::fixup_ve_pc_hi32:
69 case VE::fixup_ve_pc_lo32:
70 case VE::fixup_ve_got_hi32:
71 case VE::fixup_ve_got_lo32:
72 case VE::fixup_ve_gotoff_hi32:
73 case VE::fixup_ve_gotoff_lo32:
74 case VE::fixup_ve_plt_hi32:
75 case VE::fixup_ve_plt_lo32:
76 case VE::fixup_ve_tls_gd_hi32:
77 case VE::fixup_ve_tls_gd_lo32:
78 case VE::fixup_ve_tpoff_hi32:
79 case VE::fixup_ve_tpoff_lo32:
80 return 4;
81 case FK_Data_8:
82 case FK_PCRel_8:
83 return 8;
84 }
85}
86
87namespace {
88class VEAsmBackend : public MCAsmBackend {
89protected:
90 const Target &TheTarget;
91
92public:
93 VEAsmBackend(const Target &T)
94 : MCAsmBackend(llvm::endianness::little), TheTarget(T) {}
95
96 MCFixupKindInfo getFixupKindInfo(MCFixupKind Kind) const override {
97 const static MCFixupKindInfo Infos[VE::NumTargetFixupKinds] = {
98 // name, offset, bits, flags
99 {.Name: "fixup_ve_reflong", .TargetOffset: 0, .TargetSize: 32, .Flags: 0},
100 {.Name: "fixup_ve_srel32", .TargetOffset: 0, .TargetSize: 32, .Flags: MCFixupKindInfo::FKF_IsPCRel},
101 {.Name: "fixup_ve_hi32", .TargetOffset: 0, .TargetSize: 32, .Flags: 0},
102 {.Name: "fixup_ve_lo32", .TargetOffset: 0, .TargetSize: 32, .Flags: 0},
103 {.Name: "fixup_ve_pc_hi32", .TargetOffset: 0, .TargetSize: 32, .Flags: MCFixupKindInfo::FKF_IsPCRel},
104 {.Name: "fixup_ve_pc_lo32", .TargetOffset: 0, .TargetSize: 32, .Flags: MCFixupKindInfo::FKF_IsPCRel},
105 {.Name: "fixup_ve_got_hi32", .TargetOffset: 0, .TargetSize: 32, .Flags: 0},
106 {.Name: "fixup_ve_got_lo32", .TargetOffset: 0, .TargetSize: 32, .Flags: 0},
107 {.Name: "fixup_ve_gotoff_hi32", .TargetOffset: 0, .TargetSize: 32, .Flags: 0},
108 {.Name: "fixup_ve_gotoff_lo32", .TargetOffset: 0, .TargetSize: 32, .Flags: 0},
109 {.Name: "fixup_ve_plt_hi32", .TargetOffset: 0, .TargetSize: 32, .Flags: 0},
110 {.Name: "fixup_ve_plt_lo32", .TargetOffset: 0, .TargetSize: 32, .Flags: 0},
111 {.Name: "fixup_ve_tls_gd_hi32", .TargetOffset: 0, .TargetSize: 32, .Flags: 0},
112 {.Name: "fixup_ve_tls_gd_lo32", .TargetOffset: 0, .TargetSize: 32, .Flags: 0},
113 {.Name: "fixup_ve_tpoff_hi32", .TargetOffset: 0, .TargetSize: 32, .Flags: 0},
114 {.Name: "fixup_ve_tpoff_lo32", .TargetOffset: 0, .TargetSize: 32, .Flags: 0},
115 };
116
117 if (Kind < FirstTargetFixupKind)
118 return MCAsmBackend::getFixupKindInfo(Kind);
119
120 assert(unsigned(Kind - FirstTargetFixupKind) < VE::NumTargetFixupKinds &&
121 "Invalid kind!");
122 return Infos[Kind - FirstTargetFixupKind];
123 }
124
125 void applyFixup(const MCFragment &, const MCFixup &, const MCValue &,
126 MutableArrayRef<char>, uint64_t Value,
127 bool IsResolved) override;
128
129 bool mayNeedRelaxation(const MCInst &Inst,
130 const MCSubtargetInfo &STI) const override {
131 // Not implemented yet. For example, if we have a branch with
132 // lager than SIMM32 immediate value, we want to relaxation such
133 // branch instructions.
134 return false;
135 }
136
137 void relaxInstruction(MCInst &Inst,
138 const MCSubtargetInfo &STI) const override {
139 // Aurora VE doesn't support relaxInstruction yet.
140 llvm_unreachable("relaxInstruction() should not be called");
141 }
142
143 bool writeNopData(raw_ostream &OS, uint64_t Count,
144 const MCSubtargetInfo *STI) const override {
145 if ((Count % 8) != 0)
146 return false;
147
148 for (uint64_t i = 0; i < Count; i += 8)
149 support::endian::write<uint64_t>(os&: OS, value: 0x7900000000000000ULL,
150 endian: llvm::endianness::little);
151
152 return true;
153 }
154};
155
156class ELFVEAsmBackend : public VEAsmBackend {
157 Triple::OSType OSType;
158
159public:
160 ELFVEAsmBackend(const Target &T, Triple::OSType OSType)
161 : VEAsmBackend(T), OSType(OSType) {}
162
163 std::unique_ptr<MCObjectTargetWriter>
164 createObjectTargetWriter() const override {
165 uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(OSType);
166 return createVEELFObjectWriter(OSABI);
167 }
168};
169} // end anonymous namespace
170
171void VEAsmBackend::applyFixup(const MCFragment &F, const MCFixup &Fixup,
172 const MCValue &Target, MutableArrayRef<char> Data,
173 uint64_t Value, bool IsResolved) {
174 switch (Fixup.getTargetKind()) {
175 case VE::fixup_ve_tls_gd_hi32:
176 case VE::fixup_ve_tls_gd_lo32:
177 case VE::fixup_ve_tpoff_hi32:
178 case VE::fixup_ve_tpoff_lo32:
179 IsResolved = false;
180 break;
181 }
182 maybeAddReloc(F, Fixup, Target, Value, IsResolved);
183 Value = adjustFixupValue(Kind: Fixup.getKind(), Value);
184 if (!Value)
185 return; // Doesn't change encoding.
186
187 MCFixupKindInfo Info = getFixupKindInfo(Kind: Fixup.getKind());
188
189 // Shift the value into position.
190 Value <<= Info.TargetOffset;
191
192 unsigned NumBytes = getFixupKindNumBytes(Kind: Fixup.getKind());
193 unsigned Offset = Fixup.getOffset();
194 assert(Offset + NumBytes <= Data.size() && "Invalid fixup offset!");
195 // For each byte of the fragment that the fixup touches, mask in the bits
196 // from the fixup value. The Value has been "split up" into the
197 // appropriate bitfields above.
198 for (unsigned i = 0; i != NumBytes; ++i) {
199 unsigned Idx = Endian == llvm::endianness::little ? i : (NumBytes - 1) - i;
200 Data[Offset + Idx] |= static_cast<uint8_t>((Value >> (i * 8)) & 0xff);
201 }
202}
203
204MCAsmBackend *llvm::createVEAsmBackend(const Target &T,
205 const MCSubtargetInfo &STI,
206 const MCRegisterInfo &MRI,
207 const MCTargetOptions &Options) {
208 return new ELFVEAsmBackend(T, STI.getTargetTriple().getOS());
209}
210