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