Index: llvm/docs/LangRef.rst =================================================================== --- llvm/docs/LangRef.rst +++ llvm/docs/LangRef.rst @@ -13583,6 +13583,26 @@ optimizations that want to look for these annotations. These have no other defined use; they are ignored by code generation and optimization. +'``llvm.codeview.annotation``' Intrinsic +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: +""""""" + +This annotation emits a label at its program point and an associated +``S_ANNOTATION`` codeview record with some additional string metadata. It is +modelled as reading and writing memory, so loads and stores cannot be reordered +past it. This is used to implement MSVC's ``__annotation`` intrinsic. + +:: + + declare void @llvm.label.annotation(metadata) + +Arguments: +"""""""""" + +The argument should be an MDTuple containing any number of MDStrings. + '``llvm.trap``' Intrinsic ^^^^^^^^^^^^^^^^^^^^^^^^^ Index: llvm/include/llvm/CodeGen/ISDOpcodes.h =================================================================== --- llvm/include/llvm/CodeGen/ISDOpcodes.h +++ llvm/include/llvm/CodeGen/ISDOpcodes.h @@ -637,6 +637,12 @@ /// take a chain as input and return a chain. EH_LABEL, + /// ANNOTATION_LABEL - Represents a mid basic block label used by + /// annotations. This should remain within the basic block and be ordered + /// with respect to other call instructions, but loads and stores may float + /// past it. + ANNOTATION_LABEL, + /// CATCHPAD - Represents a catchpad instruction. CATCHPAD, Index: llvm/include/llvm/CodeGen/MachineFunction.h =================================================================== --- llvm/include/llvm/CodeGen/MachineFunction.h +++ llvm/include/llvm/CodeGen/MachineFunction.h @@ -314,6 +314,9 @@ /// Map of invoke call site index values to associated begin EH_LABEL. DenseMap CallSiteMap; + /// CodeView label annotations. + std::vector> CodeViewAnnotations; + bool CallsEHReturn = false; bool CallsUnwindInit = false; bool HasEHFunclets = false; @@ -823,6 +826,15 @@ return CallSiteMap.count(BeginLabel); } + /// Record annotations associated with a particular label. + void addCodeViewAnnotation(MCSymbol *Label, MDNode *MD) { + CodeViewAnnotations.push_back({Label, MD}); + } + + ArrayRef> getCodeViewAnnotations() const { + return CodeViewAnnotations; + } + /// Return a reference to the C++ typeinfo for the current function. const std::vector &getTypeInfos() const { return TypeInfos; Index: llvm/include/llvm/CodeGen/SelectionDAG.h =================================================================== --- llvm/include/llvm/CodeGen/SelectionDAG.h +++ llvm/include/llvm/CodeGen/SelectionDAG.h @@ -635,6 +635,8 @@ SDValue getRegister(unsigned Reg, EVT VT); SDValue getRegisterMask(const uint32_t *RegMask); SDValue getEHLabel(const SDLoc &dl, SDValue Root, MCSymbol *Label); + SDValue getLabelNode(unsigned Opcode, const SDLoc &dl, SDValue Root, + MCSymbol *Label); SDValue getBlockAddress(const BlockAddress *BA, EVT VT, int64_t Offset = 0, bool isTarget = false, unsigned char TargetFlags = 0); Index: llvm/include/llvm/CodeGen/SelectionDAGNodes.h =================================================================== --- llvm/include/llvm/CodeGen/SelectionDAGNodes.h +++ llvm/include/llvm/CodeGen/SelectionDAGNodes.h @@ -1844,19 +1844,20 @@ } }; -class EHLabelSDNode : public SDNode { +class LabelSDNode : public SDNode { friend class SelectionDAG; MCSymbol *Label; - EHLabelSDNode(unsigned Order, const DebugLoc &dl, MCSymbol *L) + LabelSDNode(unsigned Order, const DebugLoc &dl, MCSymbol *L) : SDNode(ISD::EH_LABEL, Order, dl, getSDVTList(MVT::Other)), Label(L) {} public: MCSymbol *getLabel() const { return Label; } static bool classof(const SDNode *N) { - return N->getOpcode() == ISD::EH_LABEL; + return N->getOpcode() == ISD::EH_LABEL || + N->getOpcode() == ISD::ANNOTATION_LABEL; } }; Index: llvm/include/llvm/DebugInfo/CodeView/SymbolRecord.h =================================================================== --- llvm/include/llvm/DebugInfo/CodeView/SymbolRecord.h +++ llvm/include/llvm/DebugInfo/CodeView/SymbolRecord.h @@ -942,6 +942,8 @@ uint32_t RecordOffset; }; +// S_ANNOTATION + using CVSymbol = CVRecord; using CVSymbolArray = VarStreamArray; Index: llvm/include/llvm/IR/Intrinsics.td =================================================================== --- llvm/include/llvm/IR/Intrinsics.td +++ llvm/include/llvm/IR/Intrinsics.td @@ -634,6 +634,11 @@ llvm_ptr_ty, llvm_i32_ty], [], "llvm.annotation">; +// Annotates the current program point with arbitrary metadata. It is not zero +// cost, as it is modeled as possibly reading or writing escaped memory. +def int_codeview_annotation : Intrinsic<[], [llvm_metadata_ty], [IntrNoDuplicate], + "llvm.codeview.annotation">; + //===------------------------ Trampoline Intrinsics -----------------------===// // def int_init_trampoline : Intrinsic<[], Index: llvm/include/llvm/Target/Target.td =================================================================== --- llvm/include/llvm/Target/Target.td +++ llvm/include/llvm/Target/Target.td @@ -840,6 +840,13 @@ let hasCtrlDep = 1; let isNotDuplicable = 1; } +def ANNOTATION_LABEL : Instruction { + let OutOperandList = (outs); + let InOperandList = (ins i32imm:$id); + let AsmString = ""; + let hasCtrlDep = 1; + let isNotDuplicable = 1; +} def KILL : Instruction { let OutOperandList = (outs); let InOperandList = (ins variable_ops); Index: llvm/include/llvm/Target/TargetOpcodes.def =================================================================== --- llvm/include/llvm/Target/TargetOpcodes.def +++ llvm/include/llvm/Target/TargetOpcodes.def @@ -32,6 +32,7 @@ HANDLE_TARGET_OPCODE(CFI_INSTRUCTION) HANDLE_TARGET_OPCODE(EH_LABEL) HANDLE_TARGET_OPCODE(GC_LABEL) +HANDLE_TARGET_OPCODE(ANNOTATION_LABEL) /// KILL - This instruction is a noop that is used only to adjust the /// liveness of registers. This can be useful when dealing with Index: llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h =================================================================== --- llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h +++ llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h @@ -118,6 +118,8 @@ SmallVector Locals; + std::vector> Annotations; + const MCSymbol *Begin = nullptr; const MCSymbol *End = nullptr; unsigned FuncId = 0; Index: llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp =================================================================== --- llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp +++ llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp @@ -860,6 +860,30 @@ emitInlinedCallSite(FI, InlinedAt, I->second); } + for (auto Annot : FI.Annotations) { + MCSymbol *Label = Annot.first; + MDTuple *Strs = cast(Annot.second); + MCSymbol *AnnotBegin = MMI->getContext().createTempSymbol(), + *AnnotEnd = MMI->getContext().createTempSymbol(); + OS.AddComment("Record length"); + OS.emitAbsoluteSymbolDiff(AnnotEnd, AnnotBegin, 2); + OS.EmitLabel(AnnotBegin); + OS.AddComment("Record kind: S_ANNOTATION"); + OS.EmitIntValue(SymbolKind::S_ANNOTATION, 2); + OS.EmitCOFFSecRel32(Label, /*Offset=*/0); + // FIXME: Make sure we don't overflow the max record size. + OS.EmitCOFFSectionIndex(Label); + OS.EmitIntValue(Strs->getNumOperands(), 2); + for (Metadata *MD : Strs->operands()) { + // MDStrings are null terminated, so we can do EmitBytes and get the + // nice .asciz directive. + StringRef Str = cast(MD)->getString(); + assert(Str.data()[Str.size()] == '\0' && "non-nullterminated MDString"); + OS.EmitBytes(StringRef(Str.data(), Str.size() + 1)); + } + OS.EmitLabel(AnnotEnd); + } + if (SP != nullptr) emitDebugInfoForUDTs(LocalUDTs); @@ -2152,6 +2176,8 @@ return; } + CurFn->Annotations = MF->getCodeViewAnnotations(); + CurFn->End = Asm->getFunctionEnd(); CurFn = nullptr; Index: llvm/lib/CodeGen/MachineFunction.cpp =================================================================== --- llvm/lib/CodeGen/MachineFunction.cpp +++ llvm/lib/CodeGen/MachineFunction.cpp @@ -166,6 +166,7 @@ InstructionRecycler.clear(Allocator); OperandRecycler.clear(Allocator); BasicBlockRecycler.clear(Allocator); + CodeViewAnnotations.clear(); VariableDbgInfos.clear(); if (RegInfo) { RegInfo->~MachineRegisterInfo(); Index: llvm/lib/CodeGen/SelectionDAG/InstrEmitter.cpp =================================================================== --- llvm/lib/CodeGen/SelectionDAG/InstrEmitter.cpp +++ llvm/lib/CodeGen/SelectionDAG/InstrEmitter.cpp @@ -935,10 +935,14 @@ EmitCopyFromReg(Node, 0, IsClone, IsCloned, SrcReg, VRBaseMap); break; } - case ISD::EH_LABEL: { - MCSymbol *S = cast(Node)->getLabel(); + case ISD::EH_LABEL: + case ISD::ANNOTATION_LABEL: { + unsigned Opc = (Node->getOpcode() == ISD::EH_LABEL) + ? TargetOpcode::EH_LABEL + : TargetOpcode::ANNOTATION_LABEL; + MCSymbol *S = cast(Node)->getLabel(); BuildMI(*MBB, InsertPos, Node->getDebugLoc(), - TII->get(TargetOpcode::EH_LABEL)).addSym(S); + TII->get(Opc)).addSym(S); break; } Index: llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp =================================================================== --- llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -1664,15 +1664,20 @@ SDValue SelectionDAG::getEHLabel(const SDLoc &dl, SDValue Root, MCSymbol *Label) { + return getLabelNode(ISD::EH_LABEL, dl, Root, Label); +} + +SDValue SelectionDAG::getLabelNode(unsigned Opcode, const SDLoc &dl, + SDValue Root, MCSymbol *Label) { FoldingSetNodeID ID; SDValue Ops[] = { Root }; - AddNodeIDNode(ID, ISD::EH_LABEL, getVTList(MVT::Other), Ops); + AddNodeIDNode(ID, Opcode, getVTList(MVT::Other), Ops); ID.AddPointer(Label); void *IP = nullptr; if (SDNode *E = FindNodeOrInsertPos(ID, IP)) return SDValue(E, 0); - auto *N = newSDNode(dl.getIROrder(), dl.getDebugLoc(), Label); + auto *N = newSDNode(dl.getIROrder(), dl.getDebugLoc(), Label); createOperands(N, Ops); CSEMap.InsertNode(N, IP); Index: llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp =================================================================== --- llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -5629,6 +5629,18 @@ // Discard annotate attributes and assumptions return nullptr; + case Intrinsic::codeview_annotation: { + // Emit a label associated with this metadata. + MachineFunction &MF = DAG.getMachineFunction(); + MCSymbol *Label = + MF.getMMI().getContext().createTempSymbol("annotation", true); + Metadata *MD = cast(I.getArgOperand(0))->getMetadata(); + MF.addCodeViewAnnotation(Label, cast(MD)); + Res = DAG.getLabelNode(ISD::ANNOTATION_LABEL, sdl, getRoot(), Label); + DAG.setRoot(Res); + return nullptr; + } + case Intrinsic::init_trampoline: { const Function *F = cast(I.getArgOperand(1)->stripPointerCasts()); Index: llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp =================================================================== --- llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -2911,6 +2911,7 @@ case ISD::CopyFromReg: case ISD::CopyToReg: case ISD::EH_LABEL: + case ISD::ANNOTATION_LABEL: case ISD::LIFETIME_START: case ISD::LIFETIME_END: NodeToMatch->setNodeId(-1); // Mark selected. Index: llvm/test/CodeGen/X86/label-annotation.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/X86/label-annotation.ll @@ -0,0 +1,73 @@ +; RUN: llc < %s | FileCheck %s +; FIXME: fastisel screws up the order here. +; RUNX: llc -O0 < %s | FileCheck %s + +; Source to regenerate: +; $ clang --target=x86_64-windows-msvc -S annotation.c -g -gcodeview -o t.ll \ +; -emit-llvm -O1 -Xclang -disable-llvm-passes -fms-extensions +; void g(void); +; void f(void) { +; g(); +; __annotation(L"a1", L"a2"); +; g(); +; } + +; ModuleID = 'annotation.c' +source_filename = "annotation.c" +target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-pc-windows-msvc19.0.24215" + +; Function Attrs: nounwind uwtable +define void @f() #0 !dbg !8 { +entry: + call void @g(), !dbg !11 + call void @llvm.codeview.annotation(metadata !12), !dbg !13 + call void @g(), !dbg !14 + ret void, !dbg !15 +} + +; CHECK-LABEL: f: # @f +; CHECK: callq g +; CHECK: .Lannotation0: +; CHECK: callq g +; CHECK: retq + +; CHECK-LABEL: .short 4423 # Record kind: S_GPROC32_ID +; CHECK: .short 4121 # Record kind: S_ANNOTATION +; CHECK-NEXT: .secrel32 .Lannotation0 +; CHECK-NEXT: .secidx .Lannotation0 +; CHECK-NEXT: .short 2 +; CHECK-NEXT: .asciz "a1" +; CHECK-NEXT: .asciz "a2" + +; CHECK-LABEL: .short 4431 # Record kind: S_PROC_ID_END + +declare void @g() #1 + +; Function Attrs: nounwind +declare void @llvm.codeview.annotation(metadata) #2 + +attributes #0 = { nounwind uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5, !6} +!llvm.ident = !{!7} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 6.0.0 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) +!1 = !DIFile(filename: "annotation.c", directory: "C:\5Csrc\5Cllvm-project\5Cbuild", checksumkind: CSK_MD5, checksum: "51164221112d8a5baa55a995027e4ba5") +!2 = !{} +!3 = !{i32 2, !"CodeView", i32 1} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 2} +!6 = !{i32 7, !"PIC Level", i32 2} +!7 = !{!"clang version 6.0.0 "} +!8 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 2, type: !9, isLocal: false, isDefinition: true, scopeLine: 2, flags: DIFlagPrototyped, isOptimized: true, unit: !0, variables: !2) +!9 = !DISubroutineType(types: !10) +!10 = !{null} +!11 = !DILocation(line: 3, column: 3, scope: !8) +!12 = !{!"a1", !"a2"} +!13 = !DILocation(line: 4, column: 3, scope: !8) +!14 = !DILocation(line: 5, column: 3, scope: !8) +!15 = !DILocation(line: 6, column: 1, scope: !8) Index: llvm/test/Transforms/Inline/label-annotation.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/Inline/label-annotation.ll @@ -0,0 +1,35 @@ +; Inlining should not clone label annotations. +; Currently we block all duplication for simplicity. + +; RUN: opt < %s -S -inline | FileCheck %s + +@the_global = global i32 0 + +declare void @llvm.codeview.annotation(metadata) + +define void @inlinee() { +entry: + store i32 42, i32* @the_global + call void @llvm.codeview.annotation(metadata !0) + ret void +} + +define void @caller() { +entry: + call void @inlinee() + ret void +} + +!0 = !{!"annotation"} + +; CHECK-LABEL: define void @inlinee() +; CHECK: store i32 42, i32* @the_global +; CHECK: call void @llvm.codeview.annotation(metadata !0) +; CHECK: ret void + +; CHECK-LABEL: define void @caller() +; MSVC can inline this. If we ever do, check for the store but make sure +; there is no annotation. +; CHECK: call void @inlinee() +; CHECK-NOT: call void @llvm.codeview.annotation +; CHECK: ret void