Index: llvm/docs/LangRef.rst =================================================================== --- llvm/docs/LangRef.rst +++ llvm/docs/LangRef.rst @@ -4731,10 +4731,12 @@ DILocalVariable """"""""""""""" -``DILocalVariable`` nodes represent local variables in the source language. If -the ``arg:`` field is set to non-zero, then this variable is a subprogram -parameter, and it will be included in the ``variables:`` field of its -:ref:`DISubprogram`. +``DILocalVariable`` nodes represent local variables in the source +language. If the ``arg:`` field is set to non-zero, then this variable +is a subprogram parameter, and it will be included in the +``variables:`` field of its :ref:`DISubprogram`. If the flag +``DIFlagConstant`` is set the variable is a named constant in the +source language. .. code-block:: text Index: llvm/include/llvm/BinaryFormat/Dwarf.def =================================================================== --- llvm/include/llvm/BinaryFormat/Dwarf.def +++ llvm/include/llvm/BinaryFormat/Dwarf.def @@ -403,6 +403,7 @@ HANDLE_DW_AT(0x3e01, LLVM_config_macros, 0, LLVM) HANDLE_DW_AT(0x3e02, LLVM_isysroot, 0, LLVM) HANDLE_DW_AT(0x3e03, LLVM_tag_offset, 0, LLVM) +HANDLE_DW_AT(0x3e04, LLVM_constant, 0, LLVM) // Apple extensions. HANDLE_DW_AT(0x3fe1, APPLE_optimized, 0, APPLE) HANDLE_DW_AT(0x3fe2, APPLE_flags, 0, APPLE) Index: llvm/include/llvm/IR/DebugInfoFlags.def =================================================================== --- llvm/include/llvm/IR/DebugInfoFlags.def +++ llvm/include/llvm/IR/DebugInfoFlags.def @@ -31,8 +31,7 @@ HANDLE_DI_FLAG(3, Public) HANDLE_DI_FLAG((1 << 2), FwdDecl) HANDLE_DI_FLAG((1 << 3), AppleBlock) -// Used to be BlockByRef, can be reused for anything except DICompositeType. -HANDLE_DI_FLAG((1 << 4), ReservedBit4) +HANDLE_DI_FLAG((1 << 4), Constant) HANDLE_DI_FLAG((1 << 5), Virtual) HANDLE_DI_FLAG((1 << 6), Artificial) HANDLE_DI_FLAG((1 << 7), Explicit) Index: llvm/include/llvm/IR/DebugInfoMetadata.h =================================================================== --- llvm/include/llvm/IR/DebugInfoMetadata.h +++ llvm/include/llvm/IR/DebugInfoMetadata.h @@ -2806,6 +2806,7 @@ unsigned getArg() const { return Arg; } DIFlags getFlags() const { return Flags; } + bool isConstant() const { return getFlags() & FlagConstant; } bool isArtificial() const { return getFlags() & FlagArtificial; } bool isObjectPointer() const { return getFlags() & FlagObjectPointer; } Index: llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp =================================================================== --- llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -1244,6 +1244,8 @@ addType(VariableDie, Var.getType()); if (Var.isArtificial()) addFlag(VariableDie, dwarf::DW_AT_artificial); + if (Var.isConstant()) + addFlag(VariableDie, dwarf::DW_AT_LLVM_constant); } void DwarfCompileUnit::applyLabelAttributes(const DbgLabel &Label, Index: llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h =================================================================== --- llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h +++ llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h @@ -181,12 +181,10 @@ bool hasFrameIndexExprs() const { return !FrameIndexExprs.empty(); } void addMMIEntry(const DbgVariable &V); - // Translate tag to proper Dwarf tag. + /// Determine the appropriate tag for this variable. dwarf::Tag getTag() const { - // FIXME: Why don't we just infer this tag and store it all along? if (getVariable()->isParameter()) return dwarf::DW_TAG_formal_parameter; - return dwarf::DW_TAG_variable; } @@ -199,6 +197,11 @@ return false; } + /// Return true if the source variable is an immutable constant value. + bool isConstant() const { + return getVariable()->isConstant(); + } + bool isObjectPointer() const { if (getVariable()->isObjectPointer()) return true; Index: llvm/test/DebugInfo/Generic/constants.ll =================================================================== --- /dev/null +++ llvm/test/DebugInfo/Generic/constants.ll @@ -0,0 +1,34 @@ +; RUN: %llc_dwarf -O0 -filetype=obj -o - %s | llvm-dwarfdump - | FileCheck %s +; REQUIRES: object-emission +; CHECK: DW_TAG_variable +; CHECK-NEXT: DW_AT_location +; CHECK-NEXT: DW_AT_name {{.*}}"local_constant" +; CHECK-NOT: DW_TAG +; CHECK: DW_AT_LLVM_constant (true) + +; Function Attrs: noinline nounwind optnone ssp uwtable +define void @foo() !dbg !14 { + %1 = alloca i32, align 4 + call void @llvm.dbg.declare(metadata i32* %1, metadata !17, metadata !DIExpression()), !dbg !18 + store i32 23, i32* %1, align 4, !dbg !18 + ret void, !dbg !18 +} + +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 + +attributes #1 = { nounwind readnone speculatable } + +!llvm.module.flags = !{!9, !10} +!llvm.dbg.cu = !{!2} + +!2 = distinct !DICompileUnit(language: DW_LANG_Swift, file: !3, producer: "handwritten", isOptimized: false, emissionKind: FullDebug) +!3 = !DIFile(filename: "t.swift", directory: "/") +!4 = !{} +!7 = !DIBasicType(name: "Int32", size: 32, encoding: DW_ATE_signed) +!9 = !{i32 2, !"Dwarf Version", i32 4} +!10 = !{i32 2, !"Debug Info Version", i32 3} +!14 = distinct !DISubprogram(name: "foo", scope: !3, file: !3, line: 2, type: !15, scopeLine: 2, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !4) +!15 = !DISubroutineType(types: !16) +!16 = !{null} +!17 = !DILocalVariable(name: "local_constant", flags: DIFlagConstant, scope: !14, file: !3, line: 3, type: !7) +!18 = !DILocation(line: 3, scope: !14)