Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line | 
|---|---|---|---|
| 14 | pmbaty | 1 | //===- llvm/CodeGen/AsmPrinter.h - AsmPrinter Framework ---------*- C++ -*-===// | 
| 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 contains a class to be used as the base class for target specific | ||
| 10 | // asm writers.  This class primarily handles common functionality used by | ||
| 11 | // all asm writers. | ||
| 12 | // | ||
| 13 | //===----------------------------------------------------------------------===// | ||
| 14 | |||
| 15 | #ifndef LLVM_CODEGEN_ASMPRINTER_H | ||
| 16 | #define LLVM_CODEGEN_ASMPRINTER_H | ||
| 17 | |||
| 18 | #include "llvm/ADT/DenseMap.h" | ||
| 19 | #include "llvm/ADT/DenseSet.h" | ||
| 20 | #include "llvm/ADT/MapVector.h" | ||
| 21 | #include "llvm/ADT/SmallVector.h" | ||
| 22 | #include "llvm/BinaryFormat/Dwarf.h" | ||
| 23 | #include "llvm/CodeGen/AsmPrinterHandler.h" | ||
| 24 | #include "llvm/CodeGen/DwarfStringPoolEntry.h" | ||
| 25 | #include "llvm/CodeGen/MachineFunctionPass.h" | ||
| 26 | #include "llvm/CodeGen/StackMaps.h" | ||
| 27 | #include "llvm/IR/InlineAsm.h" | ||
| 28 | #include "llvm/Support/ErrorHandling.h" | ||
| 29 | #include <cstdint> | ||
| 30 | #include <memory> | ||
| 31 | #include <utility> | ||
| 32 | #include <vector> | ||
| 33 | |||
| 34 | namespace llvm { | ||
| 35 | |||
| 36 | class AddrLabelMap; | ||
| 37 | class BasicBlock; | ||
| 38 | class BlockAddress; | ||
| 39 | class Constant; | ||
| 40 | class ConstantArray; | ||
| 41 | class DataLayout; | ||
| 42 | class DIE; | ||
| 43 | class DIEAbbrev; | ||
| 44 | class DwarfDebug; | ||
| 45 | class GCMetadataPrinter; | ||
| 46 | class GCStrategy; | ||
| 47 | class GlobalAlias; | ||
| 48 | class GlobalObject; | ||
| 49 | class GlobalValue; | ||
| 50 | class GlobalVariable; | ||
| 51 | class MachineBasicBlock; | ||
| 52 | class MachineConstantPoolValue; | ||
| 53 | class MachineDominatorTree; | ||
| 54 | class MachineFunction; | ||
| 55 | class MachineInstr; | ||
| 56 | class MachineJumpTableInfo; | ||
| 57 | class MachineLoopInfo; | ||
| 58 | class MachineModuleInfo; | ||
| 59 | class MachineOptimizationRemarkEmitter; | ||
| 60 | class MCAsmInfo; | ||
| 61 | class MCCFIInstruction; | ||
| 62 | class MCContext; | ||
| 63 | class MCExpr; | ||
| 64 | class MCInst; | ||
| 65 | class MCSection; | ||
| 66 | class MCStreamer; | ||
| 67 | class MCSubtargetInfo; | ||
| 68 | class MCSymbol; | ||
| 69 | class MCTargetOptions; | ||
| 70 | class MDNode; | ||
| 71 | class Module; | ||
| 72 | class PseudoProbeHandler; | ||
| 73 | class raw_ostream; | ||
| 74 | class StringRef; | ||
| 75 | class TargetLoweringObjectFile; | ||
| 76 | class TargetMachine; | ||
| 77 | class Twine; | ||
| 78 | |||
| 79 | namespace remarks { | ||
| 80 | class RemarkStreamer; | ||
| 81 | } | ||
| 82 | |||
| 83 | /// This class is intended to be used as a driving class for all asm writers. | ||
| 84 | class AsmPrinter : public MachineFunctionPass { | ||
| 85 | public: | ||
| 86 |   /// Target machine description. | ||
| 87 | TargetMachine &TM; | ||
| 88 | |||
| 89 |   /// Target Asm Printer information. | ||
| 90 | const MCAsmInfo *MAI; | ||
| 91 | |||
| 92 |   /// This is the context for the output file that we are streaming. This owns | ||
| 93 |   /// all of the global MC-related objects for the generated translation unit. | ||
| 94 | MCContext &OutContext; | ||
| 95 | |||
| 96 |   /// This is the MCStreamer object for the file we are generating. This | ||
| 97 |   /// contains the transient state for the current translation unit that we are | ||
| 98 |   /// generating (such as the current section etc). | ||
| 99 | std::unique_ptr<MCStreamer> OutStreamer; | ||
| 100 | |||
| 101 |   /// The current machine function. | ||
| 102 | MachineFunction *MF = nullptr; | ||
| 103 | |||
| 104 |   /// This is a pointer to the current MachineModuleInfo. | ||
| 105 | MachineModuleInfo *MMI = nullptr; | ||
| 106 | |||
| 107 |   /// This is a pointer to the current MachineDominatorTree. | ||
| 108 | MachineDominatorTree *MDT = nullptr; | ||
| 109 | |||
| 110 |   /// This is a pointer to the current MachineLoopInfo. | ||
| 111 | MachineLoopInfo *MLI = nullptr; | ||
| 112 | |||
| 113 |   /// Optimization remark emitter. | ||
| 114 | MachineOptimizationRemarkEmitter *ORE; | ||
| 115 | |||
| 116 |   /// The symbol for the entry in __patchable_function_entires. | ||
| 117 | MCSymbol *CurrentPatchableFunctionEntrySym = nullptr; | ||
| 118 | |||
| 119 |   /// The symbol for the current function. This is recalculated at the beginning | ||
| 120 |   /// of each call to runOnMachineFunction(). | ||
| 121 | MCSymbol *CurrentFnSym = nullptr; | ||
| 122 | |||
| 123 |   /// The symbol for the current function descriptor on AIX. This is created | ||
| 124 |   /// at the beginning of each call to SetupMachineFunction(). | ||
| 125 | MCSymbol *CurrentFnDescSym = nullptr; | ||
| 126 | |||
| 127 |   /// The symbol used to represent the start of the current function for the | ||
| 128 |   /// purpose of calculating its size (e.g. using the .size directive). By | ||
| 129 |   /// default, this is equal to CurrentFnSym. | ||
| 130 | MCSymbol *CurrentFnSymForSize = nullptr; | ||
| 131 | |||
| 132 |   /// Map a basic block section ID to the begin and end symbols of that section | ||
| 133 |   ///  which determine the section's range. | ||
| 134 | struct MBBSectionRange { | ||
| 135 | MCSymbol *BeginLabel, *EndLabel; | ||
| 136 | }; | ||
| 137 | |||
| 138 | MapVector<unsigned, MBBSectionRange> MBBSectionRanges; | ||
| 139 | |||
| 140 |   /// Map global GOT equivalent MCSymbols to GlobalVariables and keep track of | ||
| 141 |   /// its number of uses by other globals. | ||
| 142 | using GOTEquivUsePair = std::pair<const GlobalVariable *, unsigned>; | ||
| 143 | MapVector<const MCSymbol *, GOTEquivUsePair> GlobalGOTEquivs; | ||
| 144 | |||
| 145 |   /// struct HandlerInfo and Handlers permit users or target extended | ||
| 146 |   /// AsmPrinter to add their own handlers. | ||
| 147 | struct HandlerInfo { | ||
| 148 | std::unique_ptr<AsmPrinterHandler> Handler; | ||
| 149 |     StringRef TimerName; | ||
| 150 |     StringRef TimerDescription; | ||
| 151 |     StringRef TimerGroupName; | ||
| 152 |     StringRef TimerGroupDescription; | ||
| 153 | |||
| 154 | HandlerInfo(std::unique_ptr<AsmPrinterHandler> Handler, StringRef TimerName, | ||
| 155 | StringRef TimerDescription, StringRef TimerGroupName, | ||
| 156 |                 StringRef TimerGroupDescription) | ||
| 157 | : Handler(std::move(Handler)), TimerName(TimerName), | ||
| 158 | TimerDescription(TimerDescription), TimerGroupName(TimerGroupName), | ||
| 159 | TimerGroupDescription(TimerGroupDescription) {} | ||
| 160 | }; | ||
| 161 | |||
| 162 |   // Flags representing which CFI section is required for a function/module. | ||
| 163 | enum class CFISection : unsigned { | ||
| 164 | None = 0, ///< Do not emit either .eh_frame or .debug_frame | ||
| 165 | EH = 1, ///< Emit .eh_frame | ||
| 166 | Debug = 2 ///< Emit .debug_frame | ||
| 167 | }; | ||
| 168 | |||
| 169 | private: | ||
| 170 | MCSymbol *CurrentFnEnd = nullptr; | ||
| 171 | |||
| 172 |   /// Map a basic block section ID to the exception symbol associated with that | ||
| 173 |   /// section. Map entries are assigned and looked up via | ||
| 174 |   /// AsmPrinter::getMBBExceptionSym. | ||
| 175 | DenseMap<unsigned, MCSymbol *> MBBSectionExceptionSyms; | ||
| 176 | |||
| 177 |   // The symbol used to represent the start of the current BB section of the | ||
| 178 |   // function. This is used to calculate the size of the BB section. | ||
| 179 | MCSymbol *CurrentSectionBeginSym = nullptr; | ||
| 180 | |||
| 181 |   /// This map keeps track of which symbol is being used for the specified basic | ||
| 182 |   /// block's address of label. | ||
| 183 | std::unique_ptr<AddrLabelMap> AddrLabelSymbols; | ||
| 184 | |||
| 185 |   /// The garbage collection metadata printer table. | ||
| 186 | DenseMap<GCStrategy *, std::unique_ptr<GCMetadataPrinter>> GCMetadataPrinters; | ||
| 187 | |||
| 188 |   /// Emit comments in assembly output if this is true. | ||
| 189 | bool VerboseAsm; | ||
| 190 | |||
| 191 |   /// Output stream for the stack usage file (i.e., .su file). | ||
| 192 | std::unique_ptr<raw_fd_ostream> StackUsageStream; | ||
| 193 | |||
| 194 |   /// List of symbols to be inserted into PC sections. | ||
| 195 | DenseMap<const MDNode *, SmallVector<const MCSymbol *>> PCSectionsSymbols; | ||
| 196 | |||
| 197 | static char ID; | ||
| 198 | |||
| 199 | protected: | ||
| 200 | MCSymbol *CurrentFnBegin = nullptr; | ||
| 201 | |||
| 202 |   /// For dso_local functions, the current $local alias for the function. | ||
| 203 | MCSymbol *CurrentFnBeginLocal = nullptr; | ||
| 204 | |||
| 205 |   /// A vector of all debug/EH info emitters we should use. This vector | ||
| 206 |   /// maintains ownership of the emitters. | ||
| 207 | std::vector<HandlerInfo> Handlers; | ||
| 208 | size_t NumUserHandlers = 0; | ||
| 209 | |||
| 210 |   StackMaps SM; | ||
| 211 | |||
| 212 | private: | ||
| 213 |   /// If generated on the fly this own the instance. | ||
| 214 | std::unique_ptr<MachineDominatorTree> OwnedMDT; | ||
| 215 | |||
| 216 |   /// If generated on the fly this own the instance. | ||
| 217 | std::unique_ptr<MachineLoopInfo> OwnedMLI; | ||
| 218 | |||
| 219 |   /// If the target supports dwarf debug info, this pointer is non-null. | ||
| 220 | DwarfDebug *DD = nullptr; | ||
| 221 | |||
| 222 |   /// A handler that supports pseudo probe emission with embedded inline | ||
| 223 |   /// context. | ||
| 224 | PseudoProbeHandler *PP = nullptr; | ||
| 225 | |||
| 226 |   /// CFISection type the module needs i.e. either .eh_frame or .debug_frame. | ||
| 227 | CFISection ModuleCFISection = CFISection::None; | ||
| 228 | |||
| 229 |   /// True if the module contains split-stack functions. This is used to | ||
| 230 |   /// emit .note.GNU-split-stack section as required by the linker for | ||
| 231 |   /// special handling split-stack function calling no-split-stack function. | ||
| 232 | bool HasSplitStack = false; | ||
| 233 | |||
| 234 |   /// True if the module contains no-split-stack functions. This is used to emit | ||
| 235 |   /// .note.GNU-no-split-stack section when it also contains functions without a | ||
| 236 |   /// split stack prologue. | ||
| 237 | bool HasNoSplitStack = false; | ||
| 238 | |||
| 239 | protected: | ||
| 240 | explicit AsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer); | ||
| 241 | |||
| 242 | public: | ||
| 243 | ~AsmPrinter() override; | ||
| 244 | |||
| 245 | DwarfDebug *getDwarfDebug() { return DD; } | ||
| 246 | DwarfDebug *getDwarfDebug() const { return DD; } | ||
| 247 | |||
| 248 | uint16_t getDwarfVersion() const; | ||
| 249 | void setDwarfVersion(uint16_t Version); | ||
| 250 | |||
| 251 | bool isDwarf64() const; | ||
| 252 | |||
| 253 |   /// Returns 4 for DWARF32 and 8 for DWARF64. | ||
| 254 | unsigned int getDwarfOffsetByteSize() const; | ||
| 255 | |||
| 256 |   /// Returns 4 for DWARF32 and 12 for DWARF64. | ||
| 257 | unsigned int getUnitLengthFieldByteSize() const; | ||
| 258 | |||
| 259 |   /// Returns information about the byte size of DW_FORM values. | ||
| 260 | dwarf::FormParams getDwarfFormParams() const; | ||
| 261 | |||
| 262 | bool isPositionIndependent() const; | ||
| 263 | |||
| 264 |   /// Return true if assembly output should contain comments. | ||
| 265 | bool isVerbose() const { return VerboseAsm; } | ||
| 266 | |||
| 267 |   /// Return a unique ID for the current function. | ||
| 268 | unsigned getFunctionNumber() const; | ||
| 269 | |||
| 270 |   /// Return symbol for the function pseudo stack if the stack frame is not a | ||
| 271 |   /// register based. | ||
| 272 | virtual const MCSymbol *getFunctionFrameSymbol() const { return nullptr; } | ||
| 273 | |||
| 274 | MCSymbol *getFunctionBegin() const { return CurrentFnBegin; } | ||
| 275 | MCSymbol *getFunctionEnd() const { return CurrentFnEnd; } | ||
| 276 | |||
| 277 |   // Return the exception symbol associated with the MBB section containing a | ||
| 278 |   // given basic block. | ||
| 279 | MCSymbol *getMBBExceptionSym(const MachineBasicBlock &MBB); | ||
| 280 | |||
| 281 |   /// Return the symbol to be used for the specified basic block when its | ||
| 282 |   /// address is taken.  This cannot be its normal LBB label because the block | ||
| 283 |   /// may be accessed outside its containing function. | ||
| 284 | MCSymbol *getAddrLabelSymbol(const BasicBlock *BB) { | ||
| 285 | return getAddrLabelSymbolToEmit(BB).front(); | ||
| 286 |   } | ||
| 287 | |||
| 288 |   /// Return the symbol to be used for the specified basic block when its | ||
| 289 |   /// address is taken.  If other blocks were RAUW'd to this one, we may have | ||
| 290 |   /// to emit them as well, return the whole set. | ||
| 291 | ArrayRef<MCSymbol *> getAddrLabelSymbolToEmit(const BasicBlock *BB); | ||
| 292 | |||
| 293 |   /// If the specified function has had any references to address-taken blocks | ||
| 294 |   /// generated, but the block got deleted, return the symbol now so we can | ||
| 295 |   /// emit it.  This prevents emitting a reference to a symbol that has no | ||
| 296 |   /// definition. | ||
| 297 | void takeDeletedSymbolsForFunction(const Function *F, | ||
| 298 | std::vector<MCSymbol *> &Result); | ||
| 299 | |||
| 300 |   /// Return information about object file lowering. | ||
| 301 | const TargetLoweringObjectFile &getObjFileLowering() const; | ||
| 302 | |||
| 303 |   /// Return information about data layout. | ||
| 304 | const DataLayout &getDataLayout() const; | ||
| 305 | |||
| 306 |   /// Return the pointer size from the TargetMachine | ||
| 307 | unsigned getPointerSize() const; | ||
| 308 | |||
| 309 |   /// Return information about subtarget. | ||
| 310 | const MCSubtargetInfo &getSubtargetInfo() const; | ||
| 311 | |||
| 312 | void EmitToStreamer(MCStreamer &S, const MCInst &Inst); | ||
| 313 | |||
| 314 |   /// Emits inital debug location directive. | ||
| 315 | void emitInitialRawDwarfLocDirective(const MachineFunction &MF); | ||
| 316 | |||
| 317 |   /// Return the current section we are emitting to. | ||
| 318 | const MCSection *getCurrentSection() const; | ||
| 319 | |||
| 320 | void getNameWithPrefix(SmallVectorImpl<char> &Name, | ||
| 321 | const GlobalValue *GV) const; | ||
| 322 | |||
| 323 | MCSymbol *getSymbol(const GlobalValue *GV) const; | ||
| 324 | |||
| 325 |   /// Similar to getSymbol() but preferred for references. On ELF, this uses a | ||
| 326 |   /// local symbol if a reference to GV is guaranteed to be resolved to the | ||
| 327 |   /// definition in the same module. | ||
| 328 | MCSymbol *getSymbolPreferLocal(const GlobalValue &GV) const; | ||
| 329 | |||
| 330 | bool doesDwarfUseRelocationsAcrossSections() const { | ||
| 331 | return DwarfUsesRelocationsAcrossSections; | ||
| 332 |   } | ||
| 333 | |||
| 334 | void setDwarfUsesRelocationsAcrossSections(bool Enable) { | ||
| 335 | DwarfUsesRelocationsAcrossSections = Enable; | ||
| 336 |   } | ||
| 337 | |||
| 338 |   //===------------------------------------------------------------------===// | ||
| 339 |   // XRay instrumentation implementation. | ||
| 340 |   //===------------------------------------------------------------------===// | ||
| 341 | public: | ||
| 342 |   // This describes the kind of sled we're storing in the XRay table. | ||
| 343 | enum class SledKind : uint8_t { | ||
| 344 | FUNCTION_ENTER = 0, | ||
| 345 | FUNCTION_EXIT = 1, | ||
| 346 | TAIL_CALL = 2, | ||
| 347 | LOG_ARGS_ENTER = 3, | ||
| 348 | CUSTOM_EVENT = 4, | ||
| 349 | TYPED_EVENT = 5, | ||
| 350 | }; | ||
| 351 | |||
| 352 |   // The table will contain these structs that point to the sled, the function | ||
| 353 |   // containing the sled, and what kind of sled (and whether they should always | ||
| 354 |   // be instrumented). We also use a version identifier that the runtime can use | ||
| 355 |   // to decide what to do with the sled, depending on the version of the sled. | ||
| 356 | struct XRayFunctionEntry { | ||
| 357 | const MCSymbol *Sled; | ||
| 358 | const MCSymbol *Function; | ||
| 359 |     SledKind Kind; | ||
| 360 | bool AlwaysInstrument; | ||
| 361 | const class Function *Fn; | ||
| 362 | uint8_t Version; | ||
| 363 | |||
| 364 | void emit(int, MCStreamer *) const; | ||
| 365 | }; | ||
| 366 | |||
| 367 |   // All the sleds to be emitted. | ||
| 368 | SmallVector<XRayFunctionEntry, 4> Sleds; | ||
| 369 | |||
| 370 |   // Helper function to record a given XRay sled. | ||
| 371 | void recordSled(MCSymbol *Sled, const MachineInstr &MI, SledKind Kind, | ||
| 372 | uint8_t Version = 0); | ||
| 373 | |||
| 374 |   /// Emit a table with all XRay instrumentation points. | ||
| 375 | void emitXRayTable(); | ||
| 376 | |||
| 377 | void emitPatchableFunctionEntries(); | ||
| 378 | |||
| 379 |   //===------------------------------------------------------------------===// | ||
| 380 |   // MachineFunctionPass Implementation. | ||
| 381 |   //===------------------------------------------------------------------===// | ||
| 382 | |||
| 383 |   /// Record analysis usage. | ||
| 384 | void getAnalysisUsage(AnalysisUsage &AU) const override; | ||
| 385 | |||
| 386 |   /// Set up the AsmPrinter when we are working on a new module. If your pass | ||
| 387 |   /// overrides this, it must make sure to explicitly call this implementation. | ||
| 388 | bool doInitialization(Module &M) override; | ||
| 389 | |||
| 390 |   /// Shut down the asmprinter. If you override this in your pass, you must make | ||
| 391 |   /// sure to call it explicitly. | ||
| 392 | bool doFinalization(Module &M) override; | ||
| 393 | |||
| 394 |   /// Emit the specified function out to the OutStreamer. | ||
| 395 | bool runOnMachineFunction(MachineFunction &MF) override { | ||
| 396 | SetupMachineFunction(MF); | ||
| 397 | emitFunctionBody(); | ||
| 398 | return false; | ||
| 399 |   } | ||
| 400 | |||
| 401 |   //===------------------------------------------------------------------===// | ||
| 402 |   // Coarse grained IR lowering routines. | ||
| 403 |   //===------------------------------------------------------------------===// | ||
| 404 | |||
| 405 |   /// This should be called when a new MachineFunction is being processed from | ||
| 406 |   /// runOnMachineFunction. | ||
| 407 | virtual void SetupMachineFunction(MachineFunction &MF); | ||
| 408 | |||
| 409 |   /// This method emits the body and trailer for a function. | ||
| 410 | void emitFunctionBody(); | ||
| 411 | |||
| 412 | void emitCFIInstruction(const MachineInstr &MI); | ||
| 413 | |||
| 414 | void emitFrameAlloc(const MachineInstr &MI); | ||
| 415 | |||
| 416 | void emitStackSizeSection(const MachineFunction &MF); | ||
| 417 | |||
| 418 | void emitStackUsage(const MachineFunction &MF); | ||
| 419 | |||
| 420 | void emitBBAddrMapSection(const MachineFunction &MF); | ||
| 421 | |||
| 422 | void emitKCFITrapEntry(const MachineFunction &MF, const MCSymbol *Symbol); | ||
| 423 | virtual void emitKCFITypeId(const MachineFunction &MF); | ||
| 424 | |||
| 425 | void emitPseudoProbe(const MachineInstr &MI); | ||
| 426 | |||
| 427 | void emitRemarksSection(remarks::RemarkStreamer &RS); | ||
| 428 | |||
| 429 |   /// Emits a label as reference for PC sections. | ||
| 430 | void emitPCSectionsLabel(const MachineFunction &MF, const MDNode &MD); | ||
| 431 | |||
| 432 |   /// Emits the PC sections collected from instructions. | ||
| 433 | void emitPCSections(const MachineFunction &MF); | ||
| 434 | |||
| 435 |   /// Get the CFISection type for a function. | ||
| 436 | CFISection getFunctionCFISectionType(const Function &F) const; | ||
| 437 | |||
| 438 |   /// Get the CFISection type for a function. | ||
| 439 | CFISection getFunctionCFISectionType(const MachineFunction &MF) const; | ||
| 440 | |||
| 441 |   /// Get the CFISection type for the module. | ||
| 442 | CFISection getModuleCFISectionType() const { return ModuleCFISection; } | ||
| 443 | |||
| 444 | bool needsSEHMoves(); | ||
| 445 | |||
| 446 |   /// Since emitting CFI unwind information is entangled with supporting the | ||
| 447 |   /// exceptions, this returns true for platforms which use CFI unwind | ||
| 448 |   /// information for debugging purpose when | ||
| 449 |   /// `MCAsmInfo::ExceptionsType == ExceptionHandling::None`. | ||
| 450 | bool needsCFIForDebug() const; | ||
| 451 | |||
| 452 |   /// Print to the current output stream assembly representations of the | ||
| 453 |   /// constants in the constant pool MCP. This is used to print out constants | ||
| 454 |   /// which have been "spilled to memory" by the code generator. | ||
| 455 | virtual void emitConstantPool(); | ||
| 456 | |||
| 457 |   /// Print assembly representations of the jump tables used by the current | ||
| 458 |   /// function to the current output stream. | ||
| 459 | virtual void emitJumpTableInfo(); | ||
| 460 | |||
| 461 |   /// Emit the specified global variable to the .s file. | ||
| 462 | virtual void emitGlobalVariable(const GlobalVariable *GV); | ||
| 463 | |||
| 464 |   /// Check to see if the specified global is a special global used by LLVM. If | ||
| 465 |   /// so, emit it and return true, otherwise do nothing and return false. | ||
| 466 | bool emitSpecialLLVMGlobal(const GlobalVariable *GV); | ||
| 467 | |||
| 468 |   /// `llvm.global_ctors` and `llvm.global_dtors` are arrays of Structor | ||
| 469 |   /// structs. | ||
| 470 |   /// | ||
| 471 |   /// Priority - init priority | ||
| 472 |   /// Func - global initialization or global clean-up function | ||
| 473 |   /// ComdatKey - associated data | ||
| 474 | struct Structor { | ||
| 475 | int Priority = 0; | ||
| 476 | Constant *Func = nullptr; | ||
| 477 | GlobalValue *ComdatKey = nullptr; | ||
| 478 | |||
| 479 | Structor() = default; | ||
| 480 | }; | ||
| 481 | |||
| 482 |   /// This method gathers an array of Structors and then sorts them out by | ||
| 483 |   /// Priority. | ||
| 484 |   /// @param List The initializer of `llvm.global_ctors` or `llvm.global_dtors` | ||
| 485 |   /// array. | ||
| 486 |   /// @param[out] Structors Sorted Structor structs by Priority. | ||
| 487 | void preprocessXXStructorList(const DataLayout &DL, const Constant *List, | ||
| 488 | SmallVector<Structor, 8> &Structors); | ||
| 489 | |||
| 490 |   /// This method emits `llvm.global_ctors` or `llvm.global_dtors` list. | ||
| 491 | virtual void emitXXStructorList(const DataLayout &DL, const Constant *List, | ||
| 492 | bool IsCtor); | ||
| 493 | |||
| 494 |   /// Emit an alignment directive to the specified power of two boundary. If a | ||
| 495 |   /// global value is specified, and if that global has an explicit alignment | ||
| 496 |   /// requested, it will override the alignment request if required for | ||
| 497 |   /// correctness. | ||
| 498 | void emitAlignment(Align Alignment, const GlobalObject *GV = nullptr, | ||
| 499 | unsigned MaxBytesToEmit = 0) const; | ||
| 500 | |||
| 501 |   /// Lower the specified LLVM Constant to an MCExpr. | ||
| 502 | virtual const MCExpr *lowerConstant(const Constant *CV); | ||
| 503 | |||
| 504 |   /// Print a general LLVM constant to the .s file. | ||
| 505 |   /// On AIX, when an alias refers to a sub-element of a global variable, the | ||
| 506 |   /// label of that alias needs to be emitted before the corresponding element. | ||
| 507 | using AliasMapTy = DenseMap<uint64_t, SmallVector<const GlobalAlias *, 1>>; | ||
| 508 | void emitGlobalConstant(const DataLayout &DL, const Constant *CV, | ||
| 509 | AliasMapTy *AliasList = nullptr); | ||
| 510 | |||
| 511 |   /// Unnamed constant global variables solely contaning a pointer to | ||
| 512 |   /// another globals variable act like a global variable "proxy", or GOT | ||
| 513 |   /// equivalents, i.e., it's only used to hold the address of the latter. One | ||
| 514 |   /// optimization is to replace accesses to these proxies by using the GOT | ||
| 515 |   /// entry for the final global instead. Hence, we select GOT equivalent | ||
| 516 |   /// candidates among all the module global variables, avoid emitting them | ||
| 517 |   /// unnecessarily and finally replace references to them by pc relative | ||
| 518 |   /// accesses to GOT entries. | ||
| 519 | void computeGlobalGOTEquivs(Module &M); | ||
| 520 | |||
| 521 |   /// Constant expressions using GOT equivalent globals may not be | ||
| 522 |   /// eligible for PC relative GOT entry conversion, in such cases we need to | ||
| 523 |   /// emit the proxies we previously omitted in EmitGlobalVariable. | ||
| 524 | void emitGlobalGOTEquivs(); | ||
| 525 | |||
| 526 |   /// Emit the stack maps. | ||
| 527 | void emitStackMaps(); | ||
| 528 | |||
| 529 |   //===------------------------------------------------------------------===// | ||
| 530 |   // Overridable Hooks | ||
| 531 |   //===------------------------------------------------------------------===// | ||
| 532 | |||
| 533 | void addAsmPrinterHandler(HandlerInfo Handler) { | ||
| 534 | Handlers.insert(Handlers.begin(), std::move(Handler)); | ||
| 535 | NumUserHandlers++; | ||
| 536 |   } | ||
| 537 | |||
| 538 |   // Targets can, or in the case of EmitInstruction, must implement these to | ||
| 539 |   // customize output. | ||
| 540 | |||
| 541 |   /// This virtual method can be overridden by targets that want to emit | ||
| 542 |   /// something at the start of their file. | ||
| 543 | virtual void emitStartOfAsmFile(Module &) {} | ||
| 544 | |||
| 545 |   /// This virtual method can be overridden by targets that want to emit | ||
| 546 |   /// something at the end of their file. | ||
| 547 | virtual void emitEndOfAsmFile(Module &) {} | ||
| 548 | |||
| 549 |   /// Targets can override this to emit stuff before the first basic block in | ||
| 550 |   /// the function. | ||
| 551 | virtual void emitFunctionBodyStart() {} | ||
| 552 | |||
| 553 |   /// Targets can override this to emit stuff after the last basic block in the | ||
| 554 |   /// function. | ||
| 555 | virtual void emitFunctionBodyEnd() {} | ||
| 556 | |||
| 557 |   /// Targets can override this to emit stuff at the start of a basic block. | ||
| 558 |   /// By default, this method prints the label for the specified | ||
| 559 |   /// MachineBasicBlock, an alignment (if present) and a comment describing it | ||
| 560 |   /// if appropriate. | ||
| 561 | virtual void emitBasicBlockStart(const MachineBasicBlock &MBB); | ||
| 562 | |||
| 563 |   /// Targets can override this to emit stuff at the end of a basic block. | ||
| 564 | virtual void emitBasicBlockEnd(const MachineBasicBlock &MBB); | ||
| 565 | |||
| 566 |   /// Targets should implement this to emit instructions. | ||
| 567 | virtual void emitInstruction(const MachineInstr *) { | ||
| 568 | llvm_unreachable("EmitInstruction not implemented"); | ||
| 569 |   } | ||
| 570 | |||
| 571 |   /// Return the symbol for the specified constant pool entry. | ||
| 572 | virtual MCSymbol *GetCPISymbol(unsigned CPID) const; | ||
| 573 | |||
| 574 | virtual void emitFunctionEntryLabel(); | ||
| 575 | |||
| 576 | virtual void emitFunctionDescriptor() { | ||
| 577 | llvm_unreachable("Function descriptor is target-specific."); | ||
| 578 |   } | ||
| 579 | |||
| 580 | virtual void emitMachineConstantPoolValue(MachineConstantPoolValue *MCPV); | ||
| 581 | |||
| 582 |   /// Targets can override this to change how global constants that are part of | ||
| 583 |   /// a C++ static/global constructor list are emitted. | ||
| 584 | virtual void emitXXStructor(const DataLayout &DL, const Constant *CV) { | ||
| 585 | emitGlobalConstant(DL, CV); | ||
| 586 |   } | ||
| 587 | |||
| 588 |   /// Return true if the basic block has exactly one predecessor and the control | ||
| 589 |   /// transfer mechanism between the predecessor and this block is a | ||
| 590 |   /// fall-through. | ||
| 591 | virtual bool | ||
| 592 | isBlockOnlyReachableByFallthrough(const MachineBasicBlock *MBB) const; | ||
| 593 | |||
| 594 |   /// Targets can override this to customize the output of IMPLICIT_DEF | ||
| 595 |   /// instructions in verbose mode. | ||
| 596 | virtual void emitImplicitDef(const MachineInstr *MI) const; | ||
| 597 | |||
| 598 |   /// Emit N NOP instructions. | ||
| 599 | void emitNops(unsigned N); | ||
| 600 | |||
| 601 |   //===------------------------------------------------------------------===// | ||
| 602 |   // Symbol Lowering Routines. | ||
| 603 |   //===------------------------------------------------------------------===// | ||
| 604 | |||
| 605 | MCSymbol *createTempSymbol(const Twine &Name) const; | ||
| 606 | |||
| 607 |   /// Return the MCSymbol for a private symbol with global value name as its | ||
| 608 |   /// base, with the specified suffix. | ||
| 609 | MCSymbol *getSymbolWithGlobalValueBase(const GlobalValue *GV, | ||
| 610 | StringRef Suffix) const; | ||
| 611 | |||
| 612 |   /// Return the MCSymbol for the specified ExternalSymbol. | ||
| 613 | MCSymbol *GetExternalSymbolSymbol(StringRef Sym) const; | ||
| 614 | |||
| 615 |   /// Return the symbol for the specified jump table entry. | ||
| 616 | MCSymbol *GetJTISymbol(unsigned JTID, bool isLinkerPrivate = false) const; | ||
| 617 | |||
| 618 |   /// Return the symbol for the specified jump table .set | ||
| 619 |   /// FIXME: privatize to AsmPrinter. | ||
| 620 | MCSymbol *GetJTSetSymbol(unsigned UID, unsigned MBBID) const; | ||
| 621 | |||
| 622 |   /// Return the MCSymbol used to satisfy BlockAddress uses of the specified | ||
| 623 |   /// basic block. | ||
| 624 | MCSymbol *GetBlockAddressSymbol(const BlockAddress *BA) const; | ||
| 625 | MCSymbol *GetBlockAddressSymbol(const BasicBlock *BB) const; | ||
| 626 | |||
| 627 |   //===------------------------------------------------------------------===// | ||
| 628 |   // Emission Helper Routines. | ||
| 629 |   //===------------------------------------------------------------------===// | ||
| 630 | |||
| 631 |   /// This is just convenient handler for printing offsets. | ||
| 632 | void printOffset(int64_t Offset, raw_ostream &OS) const; | ||
| 633 | |||
| 634 |   /// Emit a byte directive and value. | ||
| 635 | void emitInt8(int Value) const; | ||
| 636 | |||
| 637 |   /// Emit a short directive and value. | ||
| 638 | void emitInt16(int Value) const; | ||
| 639 | |||
| 640 |   /// Emit a long directive and value. | ||
| 641 | void emitInt32(int Value) const; | ||
| 642 | |||
| 643 |   /// Emit a long long directive and value. | ||
| 644 | void emitInt64(uint64_t Value) const; | ||
| 645 | |||
| 646 |   /// Emit something like ".long Hi-Lo" where the size in bytes of the directive | ||
| 647 |   /// is specified by Size and Hi/Lo specify the labels.  This implicitly uses | ||
| 648 |   /// .set if it is available. | ||
| 649 | void emitLabelDifference(const MCSymbol *Hi, const MCSymbol *Lo, | ||
| 650 | unsigned Size) const; | ||
| 651 | |||
| 652 |   /// Emit something like ".uleb128 Hi-Lo". | ||
| 653 | void emitLabelDifferenceAsULEB128(const MCSymbol *Hi, | ||
| 654 | const MCSymbol *Lo) const; | ||
| 655 | |||
| 656 |   /// Emit something like ".long Label+Offset" where the size in bytes of the | ||
| 657 |   /// directive is specified by Size and Label specifies the label.  This | ||
| 658 |   /// implicitly uses .set if it is available. | ||
| 659 | void emitLabelPlusOffset(const MCSymbol *Label, uint64_t Offset, | ||
| 660 | unsigned Size, bool IsSectionRelative = false) const; | ||
| 661 | |||
| 662 |   /// Emit something like ".long Label" where the size in bytes of the directive | ||
| 663 |   /// is specified by Size and Label specifies the label. | ||
| 664 | void emitLabelReference(const MCSymbol *Label, unsigned Size, | ||
| 665 | bool IsSectionRelative = false) const { | ||
| 666 | emitLabelPlusOffset(Label, 0, Size, IsSectionRelative); | ||
| 667 |   } | ||
| 668 | |||
| 669 |   //===------------------------------------------------------------------===// | ||
| 670 |   // Dwarf Emission Helper Routines | ||
| 671 |   //===------------------------------------------------------------------===// | ||
| 672 | |||
| 673 |   /// Emit the specified signed leb128 value. | ||
| 674 | void emitSLEB128(int64_t Value, const char *Desc = nullptr) const; | ||
| 675 | |||
| 676 |   /// Emit the specified unsigned leb128 value. | ||
| 677 | void emitULEB128(uint64_t Value, const char *Desc = nullptr, | ||
| 678 | unsigned PadTo = 0) const; | ||
| 679 | |||
| 680 |   /// Emit a .byte 42 directive that corresponds to an encoding.  If verbose | ||
| 681 |   /// assembly output is enabled, we output comments describing the encoding. | ||
| 682 |   /// Desc is a string saying what the encoding is specifying (e.g. "LSDA"). | ||
| 683 | void emitEncodingByte(unsigned Val, const char *Desc = nullptr) const; | ||
| 684 | |||
| 685 |   /// Return the size of the encoding in bytes. | ||
| 686 | unsigned GetSizeOfEncodedValue(unsigned Encoding) const; | ||
| 687 | |||
| 688 |   /// Emit reference to a ttype global with a specified encoding. | ||
| 689 | virtual void emitTTypeReference(const GlobalValue *GV, unsigned Encoding); | ||
| 690 | |||
| 691 |   /// Emit a reference to a symbol for use in dwarf. Different object formats | ||
| 692 |   /// represent this in different ways. Some use a relocation others encode | ||
| 693 |   /// the label offset in its section. | ||
| 694 | void emitDwarfSymbolReference(const MCSymbol *Label, | ||
| 695 | bool ForceOffset = false) const; | ||
| 696 | |||
| 697 |   /// Emit the 4- or 8-byte offset of a string from the start of its section. | ||
| 698 |   /// | ||
| 699 |   /// When possible, emit a DwarfStringPool section offset without any | ||
| 700 |   /// relocations, and without using the symbol.  Otherwise, defers to \a | ||
| 701 |   /// emitDwarfSymbolReference(). | ||
| 702 |   /// | ||
| 703 |   /// The length of the emitted value depends on the DWARF format. | ||
| 704 | void emitDwarfStringOffset(DwarfStringPoolEntry S) const; | ||
| 705 | |||
| 706 |   /// Emit the 4-or 8-byte offset of a string from the start of its section. | ||
| 707 | void emitDwarfStringOffset(DwarfStringPoolEntryRef S) const { | ||
| 708 | emitDwarfStringOffset(S.getEntry()); | ||
| 709 |   } | ||
| 710 | |||
| 711 |   /// Emit something like ".long Label + Offset" or ".quad Label + Offset" | ||
| 712 |   /// depending on the DWARF format. | ||
| 713 | void emitDwarfOffset(const MCSymbol *Label, uint64_t Offset) const; | ||
| 714 | |||
| 715 |   /// Emit 32- or 64-bit value depending on the DWARF format. | ||
| 716 | void emitDwarfLengthOrOffset(uint64_t Value) const; | ||
| 717 | |||
| 718 |   /// Emit a unit length field. The actual format, DWARF32 or DWARF64, is chosen | ||
| 719 |   /// according to the settings. | ||
| 720 | void emitDwarfUnitLength(uint64_t Length, const Twine &Comment) const; | ||
| 721 | |||
| 722 |   /// Emit a unit length field. The actual format, DWARF32 or DWARF64, is chosen | ||
| 723 |   /// according to the settings. | ||
| 724 |   /// Return the end symbol generated inside, the caller needs to emit it. | ||
| 725 | MCSymbol *emitDwarfUnitLength(const Twine &Prefix, | ||
| 726 | const Twine &Comment) const; | ||
| 727 | |||
| 728 |   /// Emit reference to a call site with a specified encoding | ||
| 729 | void emitCallSiteOffset(const MCSymbol *Hi, const MCSymbol *Lo, | ||
| 730 | unsigned Encoding) const; | ||
| 731 |   /// Emit an integer value corresponding to the call site encoding | ||
| 732 | void emitCallSiteValue(uint64_t Value, unsigned Encoding) const; | ||
| 733 | |||
| 734 |   /// Get the value for DW_AT_APPLE_isa. Zero if no isa encoding specified. | ||
| 735 | virtual unsigned getISAEncoding() { return 0; } | ||
| 736 | |||
| 737 |   /// Emit the directive and value for debug thread local expression | ||
| 738 |   /// | ||
| 739 |   /// \p Value - The value to emit. | ||
| 740 |   /// \p Size - The size of the integer (in bytes) to emit. | ||
| 741 | virtual void emitDebugValue(const MCExpr *Value, unsigned Size) const; | ||
| 742 | |||
| 743 |   //===------------------------------------------------------------------===// | ||
| 744 |   // Dwarf Lowering Routines | ||
| 745 |   //===------------------------------------------------------------------===// | ||
| 746 | |||
| 747 |   /// Emit frame instruction to describe the layout of the frame. | ||
| 748 | void emitCFIInstruction(const MCCFIInstruction &Inst) const; | ||
| 749 | |||
| 750 |   /// Emit Dwarf abbreviation table. | ||
| 751 | template <typename T> void emitDwarfAbbrevs(const T &Abbrevs) const { | ||
| 752 |     // For each abbreviation. | ||
| 753 | for (const auto &Abbrev : Abbrevs) | ||
| 754 | emitDwarfAbbrev(*Abbrev); | ||
| 755 | |||
| 756 |     // Mark end of abbreviations. | ||
| 757 | emitULEB128(0, "EOM(3)"); | ||
| 758 |   } | ||
| 759 | |||
| 760 | void emitDwarfAbbrev(const DIEAbbrev &Abbrev) const; | ||
| 761 | |||
| 762 |   /// Recursively emit Dwarf DIE tree. | ||
| 763 | void emitDwarfDIE(const DIE &Die) const; | ||
| 764 | |||
| 765 |   //===------------------------------------------------------------------===// | ||
| 766 |   // Inline Asm Support | ||
| 767 |   //===------------------------------------------------------------------===// | ||
| 768 | |||
| 769 |   // These are hooks that targets can override to implement inline asm | ||
| 770 |   // support.  These should probably be moved out of AsmPrinter someday. | ||
| 771 | |||
| 772 |   /// Print information related to the specified machine instr that is | ||
| 773 |   /// independent of the operand, and may be independent of the instr itself. | ||
| 774 |   /// This can be useful for portably encoding the comment character or other | ||
| 775 |   /// bits of target-specific knowledge into the asmstrings.  The syntax used is | ||
| 776 |   /// ${:comment}.  Targets can override this to add support for their own | ||
| 777 |   /// strange codes. | ||
| 778 | virtual void PrintSpecial(const MachineInstr *MI, raw_ostream &OS, | ||
| 779 | StringRef Code) const; | ||
| 780 | |||
| 781 |   /// Print the MachineOperand as a symbol. Targets with complex handling of | ||
| 782 |   /// symbol references should override the base implementation. | ||
| 783 | virtual void PrintSymbolOperand(const MachineOperand &MO, raw_ostream &OS); | ||
| 784 | |||
| 785 |   /// Print the specified operand of MI, an INLINEASM instruction, using the | ||
| 786 |   /// specified assembler variant.  Targets should override this to format as | ||
| 787 |   /// appropriate.  This method can return true if the operand is erroneous. | ||
| 788 | virtual bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, | ||
| 789 | const char *ExtraCode, raw_ostream &OS); | ||
| 790 | |||
| 791 |   /// Print the specified operand of MI, an INLINEASM instruction, using the | ||
| 792 |   /// specified assembler variant as an address. Targets should override this to | ||
| 793 |   /// format as appropriate.  This method can return true if the operand is | ||
| 794 |   /// erroneous. | ||
| 795 | virtual bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, | ||
| 796 | const char *ExtraCode, raw_ostream &OS); | ||
| 797 | |||
| 798 |   /// Let the target do anything it needs to do before emitting inlineasm. | ||
| 799 |   /// \p StartInfo - the subtarget info before parsing inline asm | ||
| 800 | virtual void emitInlineAsmStart() const; | ||
| 801 | |||
| 802 |   /// Let the target do anything it needs to do after emitting inlineasm. | ||
| 803 |   /// This callback can be used restore the original mode in case the | ||
| 804 |   /// inlineasm contains directives to switch modes. | ||
| 805 |   /// \p StartInfo - the original subtarget info before inline asm | ||
| 806 |   /// \p EndInfo   - the final subtarget info after parsing the inline asm, | ||
| 807 |   ///                or NULL if the value is unknown. | ||
| 808 | virtual void emitInlineAsmEnd(const MCSubtargetInfo &StartInfo, | ||
| 809 | const MCSubtargetInfo *EndInfo) const; | ||
| 810 | |||
| 811 |   /// This emits visibility information about symbol, if this is supported by | ||
| 812 |   /// the target. | ||
| 813 | void emitVisibility(MCSymbol *Sym, unsigned Visibility, | ||
| 814 | bool IsDefinition = true) const; | ||
| 815 | |||
| 816 |   /// This emits linkage information about \p GVSym based on \p GV, if this is | ||
| 817 |   /// supported by the target. | ||
| 818 | virtual void emitLinkage(const GlobalValue *GV, MCSymbol *GVSym) const; | ||
| 819 | |||
| 820 |   /// Return the alignment for the specified \p GV. | ||
| 821 | static Align getGVAlignment(const GlobalObject *GV, const DataLayout &DL, | ||
| 822 | Align InAlign = Align(1)); | ||
| 823 | |||
| 824 | private: | ||
| 825 |   /// Private state for PrintSpecial() | ||
| 826 |   // Assign a unique ID to this machine instruction. | ||
| 827 | mutable const MachineInstr *LastMI = nullptr; | ||
| 828 | mutable unsigned LastFn = 0; | ||
| 829 | mutable unsigned Counter = ~0U; | ||
| 830 | |||
| 831 | bool DwarfUsesRelocationsAcrossSections = false; | ||
| 832 | |||
| 833 |   /// This method emits the header for the current function. | ||
| 834 | virtual void emitFunctionHeader(); | ||
| 835 | |||
| 836 |   /// This method emits a comment next to header for the current function. | ||
| 837 | virtual void emitFunctionHeaderComment(); | ||
| 838 | |||
| 839 |   /// Emit a blob of inline asm to the output streamer. | ||
| 840 |   void | ||
| 841 | emitInlineAsm(StringRef Str, const MCSubtargetInfo &STI, | ||
| 842 | const MCTargetOptions &MCOptions, | ||
| 843 | const MDNode *LocMDNode = nullptr, | ||
| 844 | InlineAsm::AsmDialect AsmDialect = InlineAsm::AD_ATT) const; | ||
| 845 | |||
| 846 |   /// This method formats and emits the specified machine instruction that is an | ||
| 847 |   /// inline asm. | ||
| 848 | void emitInlineAsm(const MachineInstr *MI) const; | ||
| 849 | |||
| 850 |   /// Add inline assembly info to the diagnostics machinery, so we can | ||
| 851 |   /// emit file and position info. Returns SrcMgr memory buffer position. | ||
| 852 | unsigned addInlineAsmDiagBuffer(StringRef AsmStr, | ||
| 853 | const MDNode *LocMDNode) const; | ||
| 854 | |||
| 855 |   //===------------------------------------------------------------------===// | ||
| 856 |   // Internal Implementation Details | ||
| 857 |   //===------------------------------------------------------------------===// | ||
| 858 | |||
| 859 | void emitJumpTableEntry(const MachineJumpTableInfo *MJTI, | ||
| 860 | const MachineBasicBlock *MBB, unsigned uid) const; | ||
| 861 | void emitLLVMUsedList(const ConstantArray *InitList); | ||
| 862 |   /// Emit llvm.ident metadata in an '.ident' directive. | ||
| 863 | void emitModuleIdents(Module &M); | ||
| 864 |   /// Emit bytes for llvm.commandline metadata. | ||
| 865 | void emitModuleCommandLines(Module &M); | ||
| 866 | |||
| 867 | GCMetadataPrinter *getOrCreateGCPrinter(GCStrategy &S); | ||
| 868 | void emitGlobalAlias(Module &M, const GlobalAlias &GA); | ||
| 869 | void emitGlobalIFunc(Module &M, const GlobalIFunc &GI); | ||
| 870 | |||
| 871 |   /// This method decides whether the specified basic block requires a label. | ||
| 872 | bool shouldEmitLabelForBasicBlock(const MachineBasicBlock &MBB) const; | ||
| 873 | |||
| 874 | protected: | ||
| 875 | virtual bool shouldEmitWeakSwiftAsyncExtendedFramePointerFlags() const { | ||
| 876 | return false; | ||
| 877 |   } | ||
| 878 | }; | ||
| 879 | |||
| 880 | } // end namespace llvm | ||
| 881 | |||
| 882 | #endif // LLVM_CODEGEN_ASMPRINTER_H |