1 | //===-- HexagonMCTargetDesc.cpp - Hexagon Target Descriptions -------------===// |
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 | // This file provides Hexagon specific target descriptions. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "MCTargetDesc/HexagonMCTargetDesc.h" |
14 | #include "HexagonDepArch.h" |
15 | #include "HexagonTargetStreamer.h" |
16 | #include "MCTargetDesc/HexagonInstPrinter.h" |
17 | #include "MCTargetDesc/HexagonMCAsmInfo.h" |
18 | #include "MCTargetDesc/HexagonMCELFStreamer.h" |
19 | #include "MCTargetDesc/HexagonMCInstrInfo.h" |
20 | #include "TargetInfo/HexagonTargetInfo.h" |
21 | #include "llvm/ADT/StringExtras.h" |
22 | #include "llvm/ADT/StringRef.h" |
23 | #include "llvm/BinaryFormat/ELF.h" |
24 | #include "llvm/MC/MCAsmBackend.h" |
25 | #include "llvm/MC/MCAssembler.h" |
26 | #include "llvm/MC/MCCodeEmitter.h" |
27 | #include "llvm/MC/MCContext.h" |
28 | #include "llvm/MC/MCDwarf.h" |
29 | #include "llvm/MC/MCELFStreamer.h" |
30 | #include "llvm/MC/MCInstrAnalysis.h" |
31 | #include "llvm/MC/MCInstrInfo.h" |
32 | #include "llvm/MC/MCObjectWriter.h" |
33 | #include "llvm/MC/MCRegisterInfo.h" |
34 | #include "llvm/MC/MCStreamer.h" |
35 | #include "llvm/MC/MCSubtargetInfo.h" |
36 | #include "llvm/MC/TargetRegistry.h" |
37 | #include "llvm/Support/ErrorHandling.h" |
38 | #include "llvm/Support/HexagonAttributes.h" |
39 | #include "llvm/Support/raw_ostream.h" |
40 | #include <cassert> |
41 | #include <cstdint> |
42 | #include <mutex> |
43 | #include <new> |
44 | #include <string> |
45 | #include <unordered_map> |
46 | |
47 | using namespace llvm; |
48 | |
49 | #define GET_INSTRINFO_MC_DESC |
50 | #define ENABLE_INSTR_PREDICATE_VERIFIER |
51 | #include "HexagonGenInstrInfo.inc" |
52 | |
53 | #define GET_SUBTARGETINFO_MC_DESC |
54 | #include "HexagonGenSubtargetInfo.inc" |
55 | |
56 | #define GET_REGINFO_MC_DESC |
57 | #include "HexagonGenRegisterInfo.inc" |
58 | |
59 | cl::opt<bool> llvm::HexagonDisableCompound |
60 | ("mno-compound" , |
61 | cl::desc("Disable looking for compound instructions for Hexagon" )); |
62 | |
63 | cl::opt<bool> llvm::HexagonDisableDuplex |
64 | ("mno-pairing" , |
65 | cl::desc("Disable looking for duplex instructions for Hexagon" )); |
66 | |
67 | namespace { // These flags are to be deprecated |
68 | cl::opt<bool> MV5("mv5" , cl::Hidden, cl::desc("Build for Hexagon V5" ), |
69 | cl::init(Val: false)); |
70 | cl::opt<bool> MV55("mv55" , cl::Hidden, cl::desc("Build for Hexagon V55" ), |
71 | cl::init(Val: false)); |
72 | cl::opt<bool> MV60("mv60" , cl::Hidden, cl::desc("Build for Hexagon V60" ), |
73 | cl::init(Val: false)); |
74 | cl::opt<bool> MV62("mv62" , cl::Hidden, cl::desc("Build for Hexagon V62" ), |
75 | cl::init(Val: false)); |
76 | cl::opt<bool> MV65("mv65" , cl::Hidden, cl::desc("Build for Hexagon V65" ), |
77 | cl::init(Val: false)); |
78 | cl::opt<bool> MV66("mv66" , cl::Hidden, cl::desc("Build for Hexagon V66" ), |
79 | cl::init(Val: false)); |
80 | cl::opt<bool> MV67("mv67" , cl::Hidden, cl::desc("Build for Hexagon V67" ), |
81 | cl::init(Val: false)); |
82 | cl::opt<bool> MV67T("mv67t" , cl::Hidden, cl::desc("Build for Hexagon V67T" ), |
83 | cl::init(Val: false)); |
84 | cl::opt<bool> MV68("mv68" , cl::Hidden, cl::desc("Build for Hexagon V68" ), |
85 | cl::init(Val: false)); |
86 | cl::opt<bool> MV69("mv69" , cl::Hidden, cl::desc("Build for Hexagon V69" ), |
87 | cl::init(Val: false)); |
88 | cl::opt<bool> MV71("mv71" , cl::Hidden, cl::desc("Build for Hexagon V71" ), |
89 | cl::init(Val: false)); |
90 | cl::opt<bool> MV71T("mv71t" , cl::Hidden, cl::desc("Build for Hexagon V71T" ), |
91 | cl::init(Val: false)); |
92 | cl::opt<bool> MV73("mv73" , cl::Hidden, cl::desc("Build for Hexagon V73" ), |
93 | cl::init(Val: false)); |
94 | } // namespace |
95 | |
96 | cl::opt<Hexagon::ArchEnum> EnableHVX( |
97 | "mhvx" , cl::desc("Enable Hexagon Vector eXtensions" ), |
98 | cl::values(clEnumValN(Hexagon::ArchEnum::V60, "v60" , "Build for HVX v60" ), |
99 | clEnumValN(Hexagon::ArchEnum::V62, "v62" , "Build for HVX v62" ), |
100 | clEnumValN(Hexagon::ArchEnum::V65, "v65" , "Build for HVX v65" ), |
101 | clEnumValN(Hexagon::ArchEnum::V66, "v66" , "Build for HVX v66" ), |
102 | clEnumValN(Hexagon::ArchEnum::V67, "v67" , "Build for HVX v67" ), |
103 | clEnumValN(Hexagon::ArchEnum::V68, "v68" , "Build for HVX v68" ), |
104 | clEnumValN(Hexagon::ArchEnum::V69, "v69" , "Build for HVX v69" ), |
105 | clEnumValN(Hexagon::ArchEnum::V71, "v71" , "Build for HVX v71" ), |
106 | clEnumValN(Hexagon::ArchEnum::V73, "v73" , "Build for HVX v73" ), |
107 | // Sentinel for no value specified. |
108 | clEnumValN(Hexagon::ArchEnum::Generic, "" , "" )), |
109 | // Sentinel for flag not present. |
110 | cl::init(Val: Hexagon::ArchEnum::NoArch), cl::ValueOptional); |
111 | |
112 | static cl::opt<bool> |
113 | DisableHVX("mno-hvx" , cl::Hidden, |
114 | cl::desc("Disable Hexagon Vector eXtensions" )); |
115 | |
116 | static cl::opt<bool> |
117 | EnableHvxIeeeFp("mhvx-ieee-fp" , cl::Hidden, |
118 | cl::desc("Enable HVX IEEE floating point extensions" )); |
119 | static cl::opt<bool> EnableHexagonCabac |
120 | ("mcabac" , cl::desc("tbd" ), cl::init(Val: false)); |
121 | |
122 | static StringRef DefaultArch = "hexagonv60" ; |
123 | |
124 | static StringRef HexagonGetArchVariant() { |
125 | if (MV5) |
126 | return "hexagonv5" ; |
127 | if (MV55) |
128 | return "hexagonv55" ; |
129 | if (MV60) |
130 | return "hexagonv60" ; |
131 | if (MV62) |
132 | return "hexagonv62" ; |
133 | if (MV65) |
134 | return "hexagonv65" ; |
135 | if (MV66) |
136 | return "hexagonv66" ; |
137 | if (MV67) |
138 | return "hexagonv67" ; |
139 | if (MV67T) |
140 | return "hexagonv67t" ; |
141 | if (MV68) |
142 | return "hexagonv68" ; |
143 | if (MV69) |
144 | return "hexagonv69" ; |
145 | if (MV71) |
146 | return "hexagonv71" ; |
147 | if (MV71T) |
148 | return "hexagonv71t" ; |
149 | if (MV73) |
150 | return "hexagonv73" ; |
151 | return "" ; |
152 | } |
153 | |
154 | StringRef Hexagon_MC::selectHexagonCPU(StringRef CPU) { |
155 | StringRef ArchV = HexagonGetArchVariant(); |
156 | if (!ArchV.empty() && !CPU.empty()) { |
157 | // Tiny cores have a "t" suffix that is discarded when creating a secondary |
158 | // non-tiny subtarget. See: addArchSubtarget |
159 | std::pair<StringRef, StringRef> ArchP = ArchV.split(Separator: 't'); |
160 | std::pair<StringRef, StringRef> CPUP = CPU.split(Separator: 't'); |
161 | if (!ArchP.first.equals(RHS: CPUP.first)) |
162 | report_fatal_error(reason: "conflicting architectures specified." ); |
163 | return CPU; |
164 | } |
165 | if (ArchV.empty()) { |
166 | if (CPU.empty()) |
167 | CPU = DefaultArch; |
168 | return CPU; |
169 | } |
170 | return ArchV; |
171 | } |
172 | |
173 | unsigned llvm::HexagonGetLastSlot() { return HexagonItinerariesV5FU::SLOT3; } |
174 | |
175 | unsigned llvm::HexagonConvertUnits(unsigned ItinUnits, unsigned *Lanes) { |
176 | enum { |
177 | CVI_NONE = 0, |
178 | CVI_XLANE = 1 << 0, |
179 | CVI_SHIFT = 1 << 1, |
180 | CVI_MPY0 = 1 << 2, |
181 | CVI_MPY1 = 1 << 3, |
182 | CVI_ZW = 1 << 4 |
183 | }; |
184 | |
185 | if (ItinUnits == HexagonItinerariesV62FU::CVI_ALL || |
186 | ItinUnits == HexagonItinerariesV62FU::CVI_ALL_NOMEM) |
187 | return (*Lanes = 4, CVI_XLANE); |
188 | else if (ItinUnits & HexagonItinerariesV62FU::CVI_MPY01 && |
189 | ItinUnits & HexagonItinerariesV62FU::CVI_XLSHF) |
190 | return (*Lanes = 2, CVI_XLANE | CVI_MPY0); |
191 | else if (ItinUnits & HexagonItinerariesV62FU::CVI_MPY01) |
192 | return (*Lanes = 2, CVI_MPY0); |
193 | else if (ItinUnits & HexagonItinerariesV62FU::CVI_XLSHF) |
194 | return (*Lanes = 2, CVI_XLANE); |
195 | else if (ItinUnits & HexagonItinerariesV62FU::CVI_XLANE && |
196 | ItinUnits & HexagonItinerariesV62FU::CVI_SHIFT && |
197 | ItinUnits & HexagonItinerariesV62FU::CVI_MPY0 && |
198 | ItinUnits & HexagonItinerariesV62FU::CVI_MPY1) |
199 | return (*Lanes = 1, CVI_XLANE | CVI_SHIFT | CVI_MPY0 | CVI_MPY1); |
200 | else if (ItinUnits & HexagonItinerariesV62FU::CVI_XLANE && |
201 | ItinUnits & HexagonItinerariesV62FU::CVI_SHIFT) |
202 | return (*Lanes = 1, CVI_XLANE | CVI_SHIFT); |
203 | else if (ItinUnits & HexagonItinerariesV62FU::CVI_MPY0 && |
204 | ItinUnits & HexagonItinerariesV62FU::CVI_MPY1) |
205 | return (*Lanes = 1, CVI_MPY0 | CVI_MPY1); |
206 | else if (ItinUnits == HexagonItinerariesV62FU::CVI_ZW) |
207 | return (*Lanes = 1, CVI_ZW); |
208 | else if (ItinUnits == HexagonItinerariesV62FU::CVI_XLANE) |
209 | return (*Lanes = 1, CVI_XLANE); |
210 | else if (ItinUnits == HexagonItinerariesV62FU::CVI_SHIFT) |
211 | return (*Lanes = 1, CVI_SHIFT); |
212 | |
213 | return (*Lanes = 0, CVI_NONE); |
214 | } |
215 | |
216 | |
217 | namespace llvm { |
218 | namespace HexagonFUnits { |
219 | bool isSlot0Only(unsigned units) { |
220 | return HexagonItinerariesV62FU::SLOT0 == units; |
221 | } |
222 | } // namespace HexagonFUnits |
223 | } // namespace llvm |
224 | |
225 | namespace { |
226 | |
227 | class HexagonTargetAsmStreamer : public HexagonTargetStreamer { |
228 | formatted_raw_ostream &OS; |
229 | bool IsVerboseAsm; |
230 | |
231 | public: |
232 | HexagonTargetAsmStreamer(MCStreamer &S, formatted_raw_ostream &OS, |
233 | bool IsVerboseAsm, MCInstPrinter &IP) |
234 | : HexagonTargetStreamer(S), OS(OS), IsVerboseAsm(IsVerboseAsm) {} |
235 | |
236 | void prettyPrintAsm(MCInstPrinter &InstPrinter, uint64_t Address, |
237 | const MCInst &Inst, const MCSubtargetInfo &STI, |
238 | raw_ostream &OS) override { |
239 | assert(HexagonMCInstrInfo::isBundle(Inst)); |
240 | assert(HexagonMCInstrInfo::bundleSize(Inst) <= HEXAGON_PACKET_SIZE); |
241 | std::string Buffer; |
242 | { |
243 | raw_string_ostream TempStream(Buffer); |
244 | InstPrinter.printInst(MI: &Inst, Address, Annot: "" , STI, OS&: TempStream); |
245 | } |
246 | StringRef Contents(Buffer); |
247 | auto PacketBundle = Contents.rsplit(Separator: '\n'); |
248 | auto HeadTail = PacketBundle.first.split(Separator: '\n'); |
249 | StringRef Separator = "\n" ; |
250 | StringRef Indent = "\t" ; |
251 | OS << "\t{\n" ; |
252 | while (!HeadTail.first.empty()) { |
253 | StringRef InstTxt; |
254 | auto Duplex = HeadTail.first.split(Separator: '\v'); |
255 | if (!Duplex.second.empty()) { |
256 | OS << Indent << Duplex.first << Separator; |
257 | InstTxt = Duplex.second; |
258 | } else if (!HeadTail.first.trim().starts_with(Prefix: "immext" )) { |
259 | InstTxt = Duplex.first; |
260 | } |
261 | if (!InstTxt.empty()) |
262 | OS << Indent << InstTxt << Separator; |
263 | HeadTail = HeadTail.second.split(Separator: '\n'); |
264 | } |
265 | |
266 | if (HexagonMCInstrInfo::isMemReorderDisabled(MCI: Inst)) |
267 | OS << "\n\t} :mem_noshuf" << PacketBundle.second; |
268 | else |
269 | OS << "\t}" << PacketBundle.second; |
270 | } |
271 | |
272 | void finish() override { finishAttributeSection(); } |
273 | |
274 | void finishAttributeSection() override {} |
275 | |
276 | void emitAttribute(unsigned Attribute, unsigned Value) override { |
277 | OS << "\t.attribute\t" << Attribute << ", " << Twine(Value); |
278 | if (IsVerboseAsm) { |
279 | StringRef Name = ELFAttrs::attrTypeAsString( |
280 | attr: Attribute, tagNameMap: HexagonAttrs::getHexagonAttributeTags()); |
281 | if (!Name.empty()) |
282 | OS << "\t// " << Name; |
283 | } |
284 | OS << "\n" ; |
285 | } |
286 | }; |
287 | |
288 | class HexagonTargetELFStreamer : public HexagonTargetStreamer { |
289 | public: |
290 | MCELFStreamer &getStreamer() { |
291 | return static_cast<MCELFStreamer &>(Streamer); |
292 | } |
293 | HexagonTargetELFStreamer(MCStreamer &S, MCSubtargetInfo const &STI) |
294 | : HexagonTargetStreamer(S) { |
295 | MCAssembler &MCA = getStreamer().getAssembler(); |
296 | MCA.setELFHeaderEFlags(Hexagon_MC::GetELFFlags(STI)); |
297 | } |
298 | |
299 | void emitCommonSymbolSorted(MCSymbol *Symbol, uint64_t Size, |
300 | unsigned ByteAlignment, |
301 | unsigned AccessSize) override { |
302 | HexagonMCELFStreamer &HexagonELFStreamer = |
303 | static_cast<HexagonMCELFStreamer &>(getStreamer()); |
304 | HexagonELFStreamer.HexagonMCEmitCommonSymbol( |
305 | Symbol, Size, ByteAlignment: Align(ByteAlignment), AccessSize); |
306 | } |
307 | |
308 | void emitLocalCommonSymbolSorted(MCSymbol *Symbol, uint64_t Size, |
309 | unsigned ByteAlignment, |
310 | unsigned AccessSize) override { |
311 | HexagonMCELFStreamer &HexagonELFStreamer = |
312 | static_cast<HexagonMCELFStreamer &>(getStreamer()); |
313 | HexagonELFStreamer.HexagonMCEmitLocalCommonSymbol( |
314 | Symbol, Size, ByteAlignment: Align(ByteAlignment), AccessSize); |
315 | } |
316 | |
317 | void finish() override { finishAttributeSection(); } |
318 | |
319 | void reset() override { AttributeSection = nullptr; } |
320 | |
321 | private: |
322 | MCSection *AttributeSection = nullptr; |
323 | |
324 | void finishAttributeSection() override { |
325 | MCELFStreamer &S = getStreamer(); |
326 | if (S.Contents.empty()) |
327 | return; |
328 | |
329 | S.emitAttributesSection(Vendor: "hexagon" , Section: ".hexagon.attributes" , |
330 | Type: ELF::SHT_HEXAGON_ATTRIBUTES, AttributeSection); |
331 | } |
332 | |
333 | void emitAttribute(uint32_t Attribute, uint32_t Value) override { |
334 | getStreamer().setAttributeItem(Attribute, Value, |
335 | /*OverwriteExisting=*/true); |
336 | } |
337 | }; |
338 | |
339 | } // end anonymous namespace |
340 | |
341 | llvm::MCInstrInfo *llvm::createHexagonMCInstrInfo() { |
342 | MCInstrInfo *X = new MCInstrInfo(); |
343 | InitHexagonMCInstrInfo(X); |
344 | return X; |
345 | } |
346 | |
347 | static MCRegisterInfo *createHexagonMCRegisterInfo(const Triple &TT) { |
348 | MCRegisterInfo *X = new MCRegisterInfo(); |
349 | InitHexagonMCRegisterInfo(X, Hexagon::R31, /*DwarfFlavour=*/0, |
350 | /*EHFlavour=*/0, /*PC=*/Hexagon::PC); |
351 | return X; |
352 | } |
353 | |
354 | static MCAsmInfo *createHexagonMCAsmInfo(const MCRegisterInfo &MRI, |
355 | const Triple &TT, |
356 | const MCTargetOptions &Options) { |
357 | MCAsmInfo *MAI = new HexagonMCAsmInfo(TT); |
358 | |
359 | // VirtualFP = (R30 + #0). |
360 | MCCFIInstruction Inst = MCCFIInstruction::cfiDefCfa( |
361 | L: nullptr, Register: MRI.getDwarfRegNum(Hexagon::RegNum: R30, isEH: true), Offset: 0); |
362 | MAI->addInitialFrameState(Inst); |
363 | |
364 | return MAI; |
365 | } |
366 | |
367 | static MCInstPrinter *createHexagonMCInstPrinter(const Triple &T, |
368 | unsigned SyntaxVariant, |
369 | const MCAsmInfo &MAI, |
370 | const MCInstrInfo &MII, |
371 | const MCRegisterInfo &MRI) |
372 | { |
373 | if (SyntaxVariant == 0) |
374 | return new HexagonInstPrinter(MAI, MII, MRI); |
375 | else |
376 | return nullptr; |
377 | } |
378 | |
379 | static MCTargetStreamer * |
380 | createMCAsmTargetStreamer(MCStreamer &S, formatted_raw_ostream &OS, |
381 | MCInstPrinter *IP, bool IsVerboseAsm) { |
382 | return new HexagonTargetAsmStreamer(S, OS, IsVerboseAsm, *IP); |
383 | } |
384 | |
385 | static MCStreamer *createMCStreamer(Triple const &T, MCContext &Context, |
386 | std::unique_ptr<MCAsmBackend> &&MAB, |
387 | std::unique_ptr<MCObjectWriter> &&OW, |
388 | std::unique_ptr<MCCodeEmitter> &&Emitter, |
389 | bool RelaxAll) { |
390 | return createHexagonELFStreamer(TT: T, Context, MAB: std::move(MAB), OW: std::move(OW), |
391 | CE: std::move(Emitter)); |
392 | } |
393 | |
394 | static MCTargetStreamer * |
395 | createHexagonObjectTargetStreamer(MCStreamer &S, const MCSubtargetInfo &STI) { |
396 | return new HexagonTargetELFStreamer(S, STI); |
397 | } |
398 | |
399 | static MCTargetStreamer *createHexagonNullTargetStreamer(MCStreamer &S) { |
400 | return new HexagonTargetStreamer(S); |
401 | } |
402 | |
403 | static void LLVM_ATTRIBUTE_UNUSED clearFeature(MCSubtargetInfo* STI, uint64_t F) { |
404 | if (STI->hasFeature(Feature: F)) |
405 | STI->ToggleFeature(FB: F); |
406 | } |
407 | |
408 | static bool LLVM_ATTRIBUTE_UNUSED checkFeature(MCSubtargetInfo* STI, uint64_t F) { |
409 | return STI->hasFeature(Feature: F); |
410 | } |
411 | |
412 | namespace { |
413 | std::string selectHexagonFS(StringRef CPU, StringRef FS) { |
414 | SmallVector<StringRef, 3> Result; |
415 | if (!FS.empty()) |
416 | Result.push_back(Elt: FS); |
417 | |
418 | switch (EnableHVX) { |
419 | case Hexagon::ArchEnum::V5: |
420 | case Hexagon::ArchEnum::V55: |
421 | break; |
422 | case Hexagon::ArchEnum::V60: |
423 | Result.push_back(Elt: "+hvxv60" ); |
424 | break; |
425 | case Hexagon::ArchEnum::V62: |
426 | Result.push_back(Elt: "+hvxv62" ); |
427 | break; |
428 | case Hexagon::ArchEnum::V65: |
429 | Result.push_back(Elt: "+hvxv65" ); |
430 | break; |
431 | case Hexagon::ArchEnum::V66: |
432 | Result.push_back(Elt: "+hvxv66" ); |
433 | break; |
434 | case Hexagon::ArchEnum::V67: |
435 | Result.push_back(Elt: "+hvxv67" ); |
436 | break; |
437 | case Hexagon::ArchEnum::V68: |
438 | Result.push_back(Elt: "+hvxv68" ); |
439 | break; |
440 | case Hexagon::ArchEnum::V69: |
441 | Result.push_back(Elt: "+hvxv69" ); |
442 | break; |
443 | case Hexagon::ArchEnum::V71: |
444 | Result.push_back(Elt: "+hvxv71" ); |
445 | break; |
446 | case Hexagon::ArchEnum::V73: |
447 | Result.push_back(Elt: "+hvxv73" ); |
448 | break; |
449 | case Hexagon::ArchEnum::Generic:{ |
450 | Result.push_back(Elt: StringSwitch<StringRef>(CPU) |
451 | .Case(S: "hexagonv60" , Value: "+hvxv60" ) |
452 | .Case(S: "hexagonv62" , Value: "+hvxv62" ) |
453 | .Case(S: "hexagonv65" , Value: "+hvxv65" ) |
454 | .Case(S: "hexagonv66" , Value: "+hvxv66" ) |
455 | .Case(S: "hexagonv67" , Value: "+hvxv67" ) |
456 | .Case(S: "hexagonv67t" , Value: "+hvxv67" ) |
457 | .Case(S: "hexagonv68" , Value: "+hvxv68" ) |
458 | .Case(S: "hexagonv69" , Value: "+hvxv69" ) |
459 | .Case(S: "hexagonv71" , Value: "+hvxv71" ) |
460 | .Case(S: "hexagonv71t" , Value: "+hvxv71" ) |
461 | .Case(S: "hexagonv73" , Value: "+hvxv73" )); |
462 | break; |
463 | } |
464 | case Hexagon::ArchEnum::NoArch: |
465 | // Sentinel if -mhvx isn't specified |
466 | break; |
467 | } |
468 | if (EnableHvxIeeeFp) |
469 | Result.push_back(Elt: "+hvx-ieee-fp" ); |
470 | if (EnableHexagonCabac) |
471 | Result.push_back(Elt: "+cabac" ); |
472 | |
473 | return join(Begin: Result.begin(), End: Result.end(), Separator: "," ); |
474 | } |
475 | } |
476 | |
477 | static bool isCPUValid(StringRef CPU) { |
478 | return Hexagon::getCpu(CPU).has_value(); |
479 | } |
480 | |
481 | namespace { |
482 | std::pair<std::string, std::string> selectCPUAndFS(StringRef CPU, |
483 | StringRef FS) { |
484 | std::pair<std::string, std::string> Result; |
485 | Result.first = std::string(Hexagon_MC::selectHexagonCPU(CPU)); |
486 | Result.second = selectHexagonFS(CPU: Result.first, FS); |
487 | return Result; |
488 | } |
489 | std::mutex ArchSubtargetMutex; |
490 | std::unordered_map<std::string, std::unique_ptr<MCSubtargetInfo const>> |
491 | ArchSubtarget; |
492 | } // namespace |
493 | |
494 | MCSubtargetInfo const * |
495 | Hexagon_MC::getArchSubtarget(MCSubtargetInfo const *STI) { |
496 | std::lock_guard<std::mutex> Lock(ArchSubtargetMutex); |
497 | auto Existing = ArchSubtarget.find(x: std::string(STI->getCPU())); |
498 | if (Existing == ArchSubtarget.end()) |
499 | return nullptr; |
500 | return Existing->second.get(); |
501 | } |
502 | |
503 | FeatureBitset Hexagon_MC::completeHVXFeatures(const FeatureBitset &S) { |
504 | using namespace Hexagon; |
505 | // Make sure that +hvx-length turns hvx on, and that "hvx" alone |
506 | // turns on hvxvNN, corresponding to the existing ArchVNN. |
507 | FeatureBitset FB = S; |
508 | unsigned CpuArch = ArchV5; |
509 | for (unsigned F : {ArchV73, ArchV71, ArchV69, ArchV68, ArchV67, ArchV66, |
510 | ArchV65, ArchV62, ArchV60, ArchV55, ArchV5}) { |
511 | if (!FB.test(F)) |
512 | continue; |
513 | CpuArch = F; |
514 | break; |
515 | } |
516 | bool UseHvx = false; |
517 | for (unsigned F : {ExtensionHVX, ExtensionHVX64B, ExtensionHVX128B}) { |
518 | if (!FB.test(F)) |
519 | continue; |
520 | UseHvx = true; |
521 | break; |
522 | } |
523 | bool HasHvxVer = false; |
524 | for (unsigned F : {ExtensionHVXV60, ExtensionHVXV62, ExtensionHVXV65, |
525 | ExtensionHVXV66, ExtensionHVXV67, ExtensionHVXV68, |
526 | ExtensionHVXV69, ExtensionHVXV71, ExtensionHVXV73}) { |
527 | if (!FB.test(F)) |
528 | continue; |
529 | HasHvxVer = true; |
530 | UseHvx = true; |
531 | break; |
532 | } |
533 | |
534 | if (!UseHvx || HasHvxVer) |
535 | return FB; |
536 | |
537 | // HasHvxVer is false, and UseHvx is true. |
538 | switch (CpuArch) { |
539 | case ArchV73: |
540 | FB.set(ExtensionHVXV73); |
541 | [[fallthrough]]; |
542 | case ArchV71: |
543 | FB.set(ExtensionHVXV71); |
544 | [[fallthrough]]; |
545 | case ArchV69: |
546 | FB.set(ExtensionHVXV69); |
547 | [[fallthrough]]; |
548 | case ArchV68: |
549 | FB.set(ExtensionHVXV68); |
550 | [[fallthrough]]; |
551 | case ArchV67: |
552 | FB.set(ExtensionHVXV67); |
553 | [[fallthrough]]; |
554 | case ArchV66: |
555 | FB.set(ExtensionHVXV66); |
556 | [[fallthrough]]; |
557 | case ArchV65: |
558 | FB.set(ExtensionHVXV65); |
559 | [[fallthrough]]; |
560 | case ArchV62: |
561 | FB.set(ExtensionHVXV62); |
562 | [[fallthrough]]; |
563 | case ArchV60: |
564 | FB.set(ExtensionHVXV60); |
565 | break; |
566 | } |
567 | return FB; |
568 | } |
569 | |
570 | MCSubtargetInfo *Hexagon_MC::createHexagonMCSubtargetInfo(const Triple &TT, |
571 | StringRef CPU, |
572 | StringRef FS) { |
573 | std::pair<std::string, std::string> Features = selectCPUAndFS(CPU, FS); |
574 | StringRef CPUName = Features.first; |
575 | StringRef ArchFS = Features.second; |
576 | |
577 | MCSubtargetInfo *X = createHexagonMCSubtargetInfoImpl( |
578 | TT, CPUName, /*TuneCPU*/ CPUName, ArchFS); |
579 | if (X != nullptr && (CPUName == "hexagonv67t" || CPUName == "hexagon71t" )) |
580 | addArchSubtarget(STI: X, FS: ArchFS); |
581 | |
582 | if (CPU.equals(RHS: "help" )) |
583 | exit(status: 0); |
584 | |
585 | if (!isCPUValid(CPU: CPUName.str())) { |
586 | errs() << "error: invalid CPU \"" << CPUName.str().c_str() |
587 | << "\" specified\n" ; |
588 | return nullptr; |
589 | } |
590 | |
591 | // Add qfloat subtarget feature by default to v68 and above |
592 | // unless explicitely disabled |
593 | if (checkFeature(X, Hexagon::ExtensionHVXV68) && |
594 | !ArchFS.contains("-hvx-qfloat" )) { |
595 | llvm::FeatureBitset Features = X->getFeatureBits(); |
596 | X->setFeatureBits(Features.set(Hexagon::ExtensionHVXQFloat)); |
597 | } |
598 | |
599 | if (HexagonDisableDuplex) { |
600 | llvm::FeatureBitset Features = X->getFeatureBits(); |
601 | X->setFeatureBits(Features.reset(Hexagon::FeatureDuplex)); |
602 | } |
603 | |
604 | X->setFeatureBits(completeHVXFeatures(S: X->getFeatureBits())); |
605 | |
606 | // The Z-buffer instructions are grandfathered in for current |
607 | // architectures but omitted for new ones. Future instruction |
608 | // sets may introduce new/conflicting z-buffer instructions. |
609 | const bool ZRegOnDefault = |
610 | (CPUName == "hexagonv67" ) || (CPUName == "hexagonv66" ); |
611 | if (ZRegOnDefault) { |
612 | llvm::FeatureBitset Features = X->getFeatureBits(); |
613 | X->setFeatureBits(Features.set(Hexagon::ExtensionZReg)); |
614 | } |
615 | |
616 | return X; |
617 | } |
618 | |
619 | void Hexagon_MC::addArchSubtarget(MCSubtargetInfo const *STI, StringRef FS) { |
620 | assert(STI != nullptr); |
621 | if (STI->getCPU().contains(Other: "t" )) { |
622 | auto ArchSTI = createHexagonMCSubtargetInfo( |
623 | TT: STI->getTargetTriple(), |
624 | CPU: STI->getCPU().substr(Start: 0, N: STI->getCPU().size() - 1), FS); |
625 | std::lock_guard<std::mutex> Lock(ArchSubtargetMutex); |
626 | ArchSubtarget[std::string(STI->getCPU())] = |
627 | std::unique_ptr<MCSubtargetInfo const>(ArchSTI); |
628 | } |
629 | } |
630 | |
631 | std::optional<unsigned> |
632 | Hexagon_MC::getHVXVersion(const FeatureBitset &Features) { |
633 | for (auto Arch : {Hexagon::ExtensionHVXV73, Hexagon::ExtensionHVXV71, |
634 | Hexagon::ExtensionHVXV69, Hexagon::ExtensionHVXV68, |
635 | Hexagon::ExtensionHVXV67, Hexagon::ExtensionHVXV66, |
636 | Hexagon::ExtensionHVXV65, Hexagon::ExtensionHVXV62, |
637 | Hexagon::ExtensionHVXV60}) |
638 | if (Features.test(Arch)) |
639 | return Arch; |
640 | return {}; |
641 | } |
642 | |
643 | unsigned Hexagon_MC::getArchVersion(const FeatureBitset &Features) { |
644 | for (auto Arch : |
645 | {Hexagon::ArchV73, Hexagon::ArchV71, Hexagon::ArchV69, Hexagon::ArchV68, |
646 | Hexagon::ArchV67, Hexagon::ArchV66, Hexagon::ArchV65, Hexagon::ArchV62, |
647 | Hexagon::ArchV60, Hexagon::ArchV55, Hexagon::ArchV5}) |
648 | if (Features.test(Arch)) |
649 | return Arch; |
650 | llvm_unreachable("Expected arch v5-v73" ); |
651 | return 0; |
652 | } |
653 | |
654 | unsigned Hexagon_MC::GetELFFlags(const MCSubtargetInfo &STI) { |
655 | return StringSwitch<unsigned>(STI.getCPU()) |
656 | .Case(S: "generic" , Value: llvm::ELF::EF_HEXAGON_MACH_V5) |
657 | .Case(S: "hexagonv5" , Value: llvm::ELF::EF_HEXAGON_MACH_V5) |
658 | .Case(S: "hexagonv55" , Value: llvm::ELF::EF_HEXAGON_MACH_V55) |
659 | .Case(S: "hexagonv60" , Value: llvm::ELF::EF_HEXAGON_MACH_V60) |
660 | .Case(S: "hexagonv62" , Value: llvm::ELF::EF_HEXAGON_MACH_V62) |
661 | .Case(S: "hexagonv65" , Value: llvm::ELF::EF_HEXAGON_MACH_V65) |
662 | .Case(S: "hexagonv66" , Value: llvm::ELF::EF_HEXAGON_MACH_V66) |
663 | .Case(S: "hexagonv67" , Value: llvm::ELF::EF_HEXAGON_MACH_V67) |
664 | .Case(S: "hexagonv67t" , Value: llvm::ELF::EF_HEXAGON_MACH_V67T) |
665 | .Case(S: "hexagonv68" , Value: llvm::ELF::EF_HEXAGON_MACH_V68) |
666 | .Case(S: "hexagonv69" , Value: llvm::ELF::EF_HEXAGON_MACH_V69) |
667 | .Case(S: "hexagonv71" , Value: llvm::ELF::EF_HEXAGON_MACH_V71) |
668 | .Case(S: "hexagonv71t" , Value: llvm::ELF::EF_HEXAGON_MACH_V71T) |
669 | .Case(S: "hexagonv73" , Value: llvm::ELF::EF_HEXAGON_MACH_V73); |
670 | } |
671 | |
672 | llvm::ArrayRef<MCPhysReg> Hexagon_MC::GetVectRegRev() { |
673 | return ArrayRef(VectRegRev); |
674 | } |
675 | |
676 | namespace { |
677 | class HexagonMCInstrAnalysis : public MCInstrAnalysis { |
678 | public: |
679 | HexagonMCInstrAnalysis(MCInstrInfo const *Info) : MCInstrAnalysis(Info) {} |
680 | |
681 | bool isUnconditionalBranch(MCInst const &Inst) const override { |
682 | //assert(!HexagonMCInstrInfo::isBundle(Inst)); |
683 | return MCInstrAnalysis::isUnconditionalBranch(Inst); |
684 | } |
685 | |
686 | bool isConditionalBranch(MCInst const &Inst) const override { |
687 | //assert(!HexagonMCInstrInfo::isBundle(Inst)); |
688 | return MCInstrAnalysis::isConditionalBranch(Inst); |
689 | } |
690 | |
691 | bool evaluateBranch(MCInst const &Inst, uint64_t Addr, |
692 | uint64_t Size, uint64_t &Target) const override { |
693 | if (!(isCall(Inst) || isUnconditionalBranch(Inst) || |
694 | isConditionalBranch(Inst))) |
695 | return false; |
696 | |
697 | //assert(!HexagonMCInstrInfo::isBundle(Inst)); |
698 | if (!HexagonMCInstrInfo::isExtendable(MCII: *Info, MCI: Inst)) |
699 | return false; |
700 | auto const &Extended(HexagonMCInstrInfo::getExtendableOperand(MCII: *Info, MCI: Inst)); |
701 | assert(Extended.isExpr()); |
702 | int64_t Value; |
703 | if (!Extended.getExpr()->evaluateAsAbsolute(Res&: Value)) |
704 | return false; |
705 | Target = Value; |
706 | return true; |
707 | } |
708 | }; |
709 | } |
710 | |
711 | static MCInstrAnalysis *createHexagonMCInstrAnalysis(const MCInstrInfo *Info) { |
712 | return new HexagonMCInstrAnalysis(Info); |
713 | } |
714 | |
715 | // Force static initialization. |
716 | extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeHexagonTargetMC() { |
717 | // Register the MC asm info. |
718 | RegisterMCAsmInfoFn X(getTheHexagonTarget(), createHexagonMCAsmInfo); |
719 | |
720 | // Register the MC instruction info. |
721 | TargetRegistry::RegisterMCInstrInfo(T&: getTheHexagonTarget(), |
722 | Fn: createHexagonMCInstrInfo); |
723 | |
724 | // Register the MC register info. |
725 | TargetRegistry::RegisterMCRegInfo(T&: getTheHexagonTarget(), |
726 | Fn: createHexagonMCRegisterInfo); |
727 | |
728 | // Register the MC subtarget info. |
729 | TargetRegistry::RegisterMCSubtargetInfo( |
730 | T&: getTheHexagonTarget(), Fn: Hexagon_MC::createHexagonMCSubtargetInfo); |
731 | |
732 | // Register the MC Code Emitter |
733 | TargetRegistry::RegisterMCCodeEmitter(T&: getTheHexagonTarget(), |
734 | Fn: createHexagonMCCodeEmitter); |
735 | |
736 | // Register the asm backend |
737 | TargetRegistry::RegisterMCAsmBackend(T&: getTheHexagonTarget(), |
738 | Fn: createHexagonAsmBackend); |
739 | |
740 | // Register the MC instruction analyzer. |
741 | TargetRegistry::RegisterMCInstrAnalysis(T&: getTheHexagonTarget(), |
742 | Fn: createHexagonMCInstrAnalysis); |
743 | |
744 | // Register the obj streamer |
745 | TargetRegistry::RegisterELFStreamer(T&: getTheHexagonTarget(), Fn: createMCStreamer); |
746 | |
747 | // Register the obj target streamer |
748 | TargetRegistry::RegisterObjectTargetStreamer( |
749 | T&: getTheHexagonTarget(), Fn: createHexagonObjectTargetStreamer); |
750 | |
751 | // Register the asm streamer |
752 | TargetRegistry::RegisterAsmTargetStreamer(T&: getTheHexagonTarget(), |
753 | Fn: createMCAsmTargetStreamer); |
754 | |
755 | // Register the null streamer |
756 | TargetRegistry::RegisterNullTargetStreamer(T&: getTheHexagonTarget(), |
757 | Fn: createHexagonNullTargetStreamer); |
758 | |
759 | // Register the MC Inst Printer |
760 | TargetRegistry::RegisterMCInstPrinter(T&: getTheHexagonTarget(), |
761 | Fn: createHexagonMCInstPrinter); |
762 | } |
763 | |