Add llvm.codeview.annotation to implement MSVC __annotation
Summary: This intrinsic represents a label with a list of associated metadata strings. It is modelled as reading and writing inaccessible memory so that it won't be removed as dead code. I think the intention is that the annotation strings should appear at most once in the debug info, so I marked it noduplicate. We are allowed to inline code with annotations as long as we strip the annotation, but that can be done later. Reviewers: majnemer Subscribers: eraman, llvm-commits, hiraditya Differential Revision: https://reviews.llvm.org/D36904 llvm-svn: 312569
This commit is contained in:
parent
3f0e4ad833
commit
e33c94f1b0
|
@ -13626,6 +13626,27 @@ with arbitrary strings. This can be useful for special purpose
|
|||
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. This is
|
||||
used to implement MSVC's ``__annotation`` intrinsic. It is marked
|
||||
``noduplicate``, so calls to this intrinsic prevent inlining and should be
|
||||
considered expensive.
|
||||
|
||||
::
|
||||
|
||||
declare void @llvm.codeview.annotation(metadata)
|
||||
|
||||
Arguments:
|
||||
""""""""""
|
||||
|
||||
The argument should be an MDTuple containing any number of MDStrings.
|
||||
|
||||
'``llvm.trap``' Intrinsic
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
|
|
@ -638,6 +638,12 @@ namespace ISD {
|
|||
/// 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,
|
||||
|
||||
|
|
|
@ -314,6 +314,9 @@ class MachineFunction {
|
|||
/// Map of invoke call site index values to associated begin EH_LABEL.
|
||||
DenseMap<MCSymbol*, unsigned> CallSiteMap;
|
||||
|
||||
/// CodeView label annotations.
|
||||
std::vector<std::pair<MCSymbol *, MDNode *>> CodeViewAnnotations;
|
||||
|
||||
bool CallsEHReturn = false;
|
||||
bool CallsUnwindInit = false;
|
||||
bool HasEHFunclets = false;
|
||||
|
@ -832,6 +835,15 @@ public:
|
|||
return CallSiteMap.count(BeginLabel);
|
||||
}
|
||||
|
||||
/// Record annotations associated with a particular label.
|
||||
void addCodeViewAnnotation(MCSymbol *Label, MDNode *MD) {
|
||||
CodeViewAnnotations.push_back({Label, MD});
|
||||
}
|
||||
|
||||
ArrayRef<std::pair<MCSymbol *, MDNode *>> getCodeViewAnnotations() const {
|
||||
return CodeViewAnnotations;
|
||||
}
|
||||
|
||||
/// Return a reference to the C++ typeinfo for the current function.
|
||||
const std::vector<const GlobalValue *> &getTypeInfos() const {
|
||||
return TypeInfos;
|
||||
|
|
|
@ -635,6 +635,8 @@ public:
|
|||
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);
|
||||
|
|
|
@ -1848,19 +1848,20 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -942,6 +942,8 @@ public:
|
|||
uint32_t RecordOffset;
|
||||
};
|
||||
|
||||
// S_ANNOTATION
|
||||
|
||||
using CVSymbol = CVRecord<SymbolKind>;
|
||||
using CVSymbolArray = VarStreamArray<CVSymbol>;
|
||||
|
||||
|
|
|
@ -641,6 +641,13 @@ def int_annotation : Intrinsic<[llvm_anyint_ty],
|
|||
llvm_ptr_ty, llvm_i32_ty],
|
||||
[], "llvm.annotation">;
|
||||
|
||||
// Annotates the current program point with metadata strings which are emitted
|
||||
// as CodeView debug info records. This is expensive, as it disables inlining
|
||||
// and is modelled as having side effects.
|
||||
def int_codeview_annotation : Intrinsic<[], [llvm_metadata_ty],
|
||||
[IntrInaccessibleMemOnly, IntrNoDuplicate],
|
||||
"llvm.codeview.annotation">;
|
||||
|
||||
//===------------------------ Trampoline Intrinsics -----------------------===//
|
||||
//
|
||||
def int_init_trampoline : Intrinsic<[],
|
||||
|
|
|
@ -840,6 +840,13 @@ def GC_LABEL : Instruction {
|
|||
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);
|
||||
|
|
|
@ -32,6 +32,7 @@ HANDLE_TARGET_OPCODE(INLINEASM)
|
|||
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
|
||||
|
|
|
@ -860,6 +860,30 @@ void CodeViewDebug::emitDebugInfoForFunction(const Function *GV,
|
|||
emitInlinedCallSite(FI, InlinedAt, I->second);
|
||||
}
|
||||
|
||||
for (auto Annot : FI.Annotations) {
|
||||
MCSymbol *Label = Annot.first;
|
||||
MDTuple *Strs = cast<MDTuple>(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<MDString>(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);
|
||||
|
||||
|
@ -2195,6 +2219,8 @@ void CodeViewDebug::endFunctionImpl(const MachineFunction *MF) {
|
|||
return;
|
||||
}
|
||||
|
||||
CurFn->Annotations = MF->getCodeViewAnnotations();
|
||||
|
||||
CurFn->End = Asm->getFunctionEnd();
|
||||
|
||||
CurFn = nullptr;
|
||||
|
|
|
@ -119,6 +119,8 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase {
|
|||
|
||||
SmallVector<LocalVariable, 1> Locals;
|
||||
|
||||
std::vector<std::pair<MCSymbol *, MDNode *>> Annotations;
|
||||
|
||||
const MCSymbol *Begin = nullptr;
|
||||
const MCSymbol *End = nullptr;
|
||||
unsigned FuncId = 0;
|
||||
|
|
|
@ -166,6 +166,7 @@ void MachineFunction::clear() {
|
|||
InstructionRecycler.clear(Allocator);
|
||||
OperandRecycler.clear(Allocator);
|
||||
BasicBlockRecycler.clear(Allocator);
|
||||
CodeViewAnnotations.clear();
|
||||
VariableDbgInfos.clear();
|
||||
if (RegInfo) {
|
||||
RegInfo->~MachineRegisterInfo();
|
||||
|
|
|
@ -935,10 +935,14 @@ EmitSpecialNode(SDNode *Node, bool IsClone, bool IsCloned,
|
|||
EmitCopyFromReg(Node, 0, IsClone, IsCloned, SrcReg, VRBaseMap);
|
||||
break;
|
||||
}
|
||||
case ISD::EH_LABEL: {
|
||||
MCSymbol *S = cast<EHLabelSDNode>(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<LabelSDNode>(Node)->getLabel();
|
||||
BuildMI(*MBB, InsertPos, Node->getDebugLoc(),
|
||||
TII->get(TargetOpcode::EH_LABEL)).addSym(S);
|
||||
TII->get(Opc)).addSym(S);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -1680,15 +1680,20 @@ SDValue SelectionDAG::getRegisterMask(const uint32_t *RegMask) {
|
|||
|
||||
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<EHLabelSDNode>(dl.getIROrder(), dl.getDebugLoc(), Label);
|
||||
auto *N = newSDNode<LabelSDNode>(dl.getIROrder(), dl.getDebugLoc(), Label);
|
||||
createOperands(N, Ops);
|
||||
|
||||
CSEMap.InsertNode(N, IP);
|
||||
|
|
|
@ -5651,6 +5651,18 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) {
|
|||
// 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<MetadataAsValue>(I.getArgOperand(0))->getMetadata();
|
||||
MF.addCodeViewAnnotation(Label, cast<MDNode>(MD));
|
||||
Res = DAG.getLabelNode(ISD::ANNOTATION_LABEL, sdl, getRoot(), Label);
|
||||
DAG.setRoot(Res);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
case Intrinsic::init_trampoline: {
|
||||
const Function *F = cast<Function>(I.getArgOperand(1)->stripPointerCasts());
|
||||
|
||||
|
|
|
@ -2911,6 +2911,7 @@ void SelectionDAGISel::SelectCodeCommon(SDNode *NodeToMatch,
|
|||
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.
|
||||
|
|
|
@ -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)
|
|
@ -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
|
Loading…
Reference in New Issue