[llvm] [MIR] Replace bespoke DIExpression parser (PR #96827)

Scott Linder via llvm-commits llvm-commits at lists.llvm.org
Wed Jun 26 15:25:45 PDT 2024


https://github.com/slinder1 created https://github.com/llvm/llvm-project/pull/96827

Resolve FIXME by using the LLParser implementation of parseDIExpression from the MIParser.

>From c6cae2d66ef9cc999939659186cda8d2c82c13bb Mon Sep 17 00:00:00 2001
From: Scott Linder <Scott.Linder at amd.com>
Date: Wed, 26 Jun 2024 21:11:00 +0000
Subject: [PATCH 1/2] [NFC] Add DIExpression MIParser tests

Prepare for patch to replace MIParser implementation of DIExpression
parser with the LLParser version.
---
 .../CodeGen/MIR/Generic/diexpression-err.mir  | 152 ++++++++++++++++
 .../test/CodeGen/MIR/Generic/diexpression.mir | 167 ++++++++++++++++++
 2 files changed, 319 insertions(+)
 create mode 100644 llvm/test/CodeGen/MIR/Generic/diexpression-err.mir
 create mode 100644 llvm/test/CodeGen/MIR/Generic/diexpression.mir

diff --git a/llvm/test/CodeGen/MIR/Generic/diexpression-err.mir b/llvm/test/CodeGen/MIR/Generic/diexpression-err.mir
new file mode 100644
index 0000000000000..394c0d5d48eaa
--- /dev/null
+++ b/llvm/test/CodeGen/MIR/Generic/diexpression-err.mir
@@ -0,0 +1,152 @@
+# RUN: not llc -run-pass none -o - %s 2>&1 | FileCheck %s
+# Note: generated via:
+# printf 'extern long long sink; int func(int arg) { int purelocal = arg * 42; int pinnedlocal = arg * 43; sink = (long long)&pinnedlocal; return purelocal; }' | clang -cc1 -O1 -triple x86_64-unknown-linux-gnu -debug-info-kind=limited -S -mllvm -stop-after=x86-isel - -o -
+--- |
+  source_filename = "-"
+  target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+  target triple = "x86_64-unknown-linux-gnu"
+
+  @sink = external local_unnamed_addr global i64, align 8
+
+  define dso_local i32 @func(i32 noundef %arg) local_unnamed_addr #0 !dbg !8 {
+  entry:
+    %pinnedlocal = alloca i32, align 4, !DIAssignID !16
+      #dbg_assign(i1 undef, !15, !DIExpression(), !16, ptr %pinnedlocal, !DIExpression(), !17)
+      #dbg_value(i32 %arg, !13, !DIExpression(), !17)
+    %mul = mul nsw i32 %arg, 42, !dbg !18
+      #dbg_value(i32 %mul, !14, !DIExpression(), !17)
+    call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %pinnedlocal) #2, !dbg !19
+    %mul1 = mul nsw i32 %arg, 43, !dbg !20
+    store i32 %mul1, ptr %pinnedlocal, align 4, !dbg !21, !tbaa !22, !DIAssignID !26
+      #dbg_assign(i32 %mul1, !15, !DIExpression(), !26, ptr %pinnedlocal, !DIExpression(), !17)
+    %0 = ptrtoint ptr %pinnedlocal to i64, !dbg !27
+    store i64 %0, ptr @sink, align 8, !dbg !28, !tbaa !29
+    call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %pinnedlocal) #2, !dbg !31
+    ret i32 %mul, !dbg !32
+  }
+
+  declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) #1
+
+  declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) #1
+
+  attributes #0 = { mustprogress nofree norecurse nosync nounwind willreturn memory(write, argmem: none, inaccessiblemem: none) "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" }
+  attributes #1 = { mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
+  attributes #2 = { nounwind }
+
+  !llvm.dbg.cu = !{!0}
+  !llvm.module.flags = !{!4, !5, !6}
+  !llvm.ident = !{!7}
+
+  !0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "clang version 19.0.0git (git at github.com:slinder1/llvm-project.git a32b7199f0c15ea1c6c9490b6166c019c9d4bd2b)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, retainedTypes: !2, splitDebugInlining: false, nameTableKind: None)
+  !1 = !DIFile(filename: "<stdin>", directory: "/home/slinder1/llvm-project/main")
+  !2 = !{!3}
+  !3 = !DIBasicType(name: "long long", size: 64, encoding: DW_ATE_signed)
+  !4 = !{i32 2, !"Debug Info Version", i32 3}
+  !5 = !{i32 1, !"wchar_size", i32 4}
+  !6 = !{i32 7, !"debug-info-assignment-tracking", i1 true}
+  !7 = !{!"clang version 19.0.0git (git at github.com:slinder1/llvm-project.git a32b7199f0c15ea1c6c9490b6166c019c9d4bd2b)"}
+  !8 = distinct !DISubprogram(name: "func", scope: !1, file: !1, line: 1, type: !9, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !12)
+  !9 = !DISubroutineType(types: !10)
+  !10 = !{!11, !11}
+  !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+  !12 = !{!13, !14, !15}
+  !13 = !DILocalVariable(name: "arg", arg: 1, scope: !8, file: !1, line: 1, type: !11)
+  !14 = !DILocalVariable(name: "purelocal", scope: !8, file: !1, line: 1, type: !11)
+  !15 = !DILocalVariable(name: "pinnedlocal", scope: !8, file: !1, line: 1, type: !11)
+  !16 = distinct !DIAssignID()
+  !17 = !DILocation(line: 0, scope: !8)
+  !18 = !DILocation(line: 1, column: 64, scope: !8)
+  !19 = !DILocation(line: 1, column: 70, scope: !8)
+  !20 = !DILocation(line: 1, column: 92, scope: !8)
+  !21 = !DILocation(line: 1, column: 74, scope: !8)
+  !22 = !{!23, !23, i64 0}
+  !23 = !{!"int", !24, i64 0}
+  !24 = !{!"omnipotent char", !25, i64 0}
+  !25 = !{!"Simple C/C++ TBAA"}
+  !26 = distinct !DIAssignID()
+  !27 = !DILocation(line: 1, column: 105, scope: !8)
+  !28 = !DILocation(line: 1, column: 103, scope: !8)
+  !29 = !{!30, !30, i64 0}
+  !30 = !{!"long long", !24, i64 0}
+  !31 = !DILocation(line: 1, column: 148, scope: !8)
+  !32 = !DILocation(line: 1, column: 130, scope: !8)
+
+...
+---
+name:            func
+alignment:       16
+exposesReturnsTwice: false
+legalized:       false
+regBankSelected: false
+selected:        false
+failedISel:      false
+tracksRegLiveness: true
+hasWinCFI:       false
+callsEHReturn:   false
+callsUnwindInit: false
+hasEHCatchret:   false
+hasEHScopes:     false
+hasEHFunclets:   false
+isOutlined:      false
+debugInstrRef:   true
+failsVerification: false
+tracksDebugUserValues: false
+registers:
+  - { id: 0, class: gr32, preferred-register: '' }
+  - { id: 1, class: gr32, preferred-register: '' }
+  - { id: 2, class: gr64, preferred-register: '' }
+  - { id: 3, class: gr64, preferred-register: '' }
+liveins:
+  - { reg: '$edi', virtual-reg: '%0' }
+frameInfo:
+  isFrameAddressTaken: false
+  isReturnAddressTaken: false
+  hasStackMap:     false
+  hasPatchPoint:   false
+  stackSize:       0
+  offsetAdjustment: 0
+  maxAlignment:    4
+  adjustsStack:    false
+  hasCalls:        false
+  stackProtector:  ''
+  functionContext: ''
+  maxCallFrameSize: 4294967295
+  cvBytesOfCalleeSavedRegisters: 0
+  hasOpaqueSPAdjustment: false
+  hasVAStart:      false
+  hasMustTailInVarArgFunc: false
+  hasTailCall:     false
+  isCalleeSavedInfoValid: false
+  localFrameSize:  0
+  savePoint:       ''
+  restorePoint:    ''
+fixedStack:      []
+stack:
+  - { id: 0, name: pinnedlocal, type: default, offset: 0, size: 4, alignment: 4,
+      stack-id: default, callee-saved-register: '', callee-saved-restored: true,
+      debug-info-variable: '!15', debug-info-expression: '!DIExpression()',
+      debug-info-location: '!17' }
+entry_values:    []
+callSites:       []
+debugValueSubstitutions: []
+constants:       []
+machineFunctionInfo:
+  amxProgModel:    None
+body:             |
+  bb.0.entry:
+    liveins: $edi
+
+    DBG_VALUE $edi, $noreg, !13, !DIExpression(), debug-location !17
+    %0:gr32 = COPY $edi
+    %1:gr32 = nsw IMUL32rri %0, 42, implicit-def dead $eflags, debug-instr-number 1, debug-location !18
+    ; CHECK: {{.*}}.mir:[[#@LINE+1]]:38: invalid DWARF op 'W_OP_LLVM_arg'
+    DBG_INSTR_REF !14, !DIExpression(W_OP_LLVM_arg, 0), dbg-instr-ref(1, 0), debug-location !17
+    LIFETIME_START %stack.0.pinnedlocal, debug-location !19
+    %2:gr64 = MOV64rm $rip, 1, $noreg, target-flags(x86-gotpcrel) @sink, $noreg, debug-location !28 :: (load (s64) from got)
+    %3:gr64 = LEA64r %stack.0.pinnedlocal, 1, $noreg, 0, $noreg
+    MOV64mr killed %2, 1, $noreg, 0, $noreg, killed %3, debug-location !28 :: (store (s64) into @sink, !tbaa !29)
+    LIFETIME_END %stack.0.pinnedlocal, debug-location !31
+    $eax = COPY %1, debug-location !32
+    RET 0, $eax, debug-location !32
+
+...
diff --git a/llvm/test/CodeGen/MIR/Generic/diexpression.mir b/llvm/test/CodeGen/MIR/Generic/diexpression.mir
new file mode 100644
index 0000000000000..085c16fd7d6d6
--- /dev/null
+++ b/llvm/test/CodeGen/MIR/Generic/diexpression.mir
@@ -0,0 +1,167 @@
+# NOTE: Hand-modified after being autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 5
+# RUN: llc -run-pass none -o - %s 2>&1 | FileCheck %s
+# Note: generated via:
+# printf 'extern long long sink; int func(int arg) { int purelocal = arg * 42; int pinnedlocal = arg * 43; sink = (long long)&pinnedlocal; return purelocal; }' | clang -cc1 -O1 -triple x86_64-unknown-linux-gnu -debug-info-kind=limited -S -mllvm -stop-after=x86-isel - -o -
+--- |
+  source_filename = "-"
+  target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+  target triple = "x86_64-unknown-linux-gnu"
+
+  @sink = external local_unnamed_addr global i64, align 8
+
+  define dso_local i32 @func(i32 noundef %arg) local_unnamed_addr #0 !dbg !8 {
+  entry:
+    %pinnedlocal = alloca i32, align 4, !DIAssignID !16
+      #dbg_assign(i1 undef, !15, !DIExpression(), !16, ptr %pinnedlocal, !DIExpression(), !17)
+      #dbg_value(i32 %arg, !13, !DIExpression(), !17)
+    %mul = mul nsw i32 %arg, 42, !dbg !18
+      #dbg_value(i32 %mul, !14, !DIExpression(), !17)
+    call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %pinnedlocal) #2, !dbg !19
+    %mul1 = mul nsw i32 %arg, 43, !dbg !20
+    store i32 %mul1, ptr %pinnedlocal, align 4, !dbg !21, !tbaa !22, !DIAssignID !26
+      #dbg_assign(i32 %mul1, !15, !DIExpression(), !26, ptr %pinnedlocal, !DIExpression(), !17)
+    %0 = ptrtoint ptr %pinnedlocal to i64, !dbg !27
+    store i64 %0, ptr @sink, align 8, !dbg !28, !tbaa !29
+    call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %pinnedlocal) #2, !dbg !31
+    ret i32 %mul, !dbg !32
+  }
+
+  declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) #1
+
+  declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) #1
+
+  attributes #0 = { mustprogress nofree norecurse nosync nounwind willreturn memory(write, argmem: none, inaccessiblemem: none) "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" }
+  attributes #1 = { mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
+  attributes #2 = { nounwind }
+
+  !llvm.dbg.cu = !{!0}
+  !llvm.module.flags = !{!4, !5, !6}
+  !llvm.ident = !{!7}
+
+  !0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "clang version 19.0.0git (git at github.com:slinder1/llvm-project.git a32b7199f0c15ea1c6c9490b6166c019c9d4bd2b)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, retainedTypes: !2, splitDebugInlining: false, nameTableKind: None)
+  !1 = !DIFile(filename: "<stdin>", directory: "/home/slinder1/llvm-project/main")
+  !2 = !{!3}
+  !3 = !DIBasicType(name: "long long", size: 64, encoding: DW_ATE_signed)
+  !4 = !{i32 2, !"Debug Info Version", i32 3}
+  !5 = !{i32 1, !"wchar_size", i32 4}
+  !6 = !{i32 7, !"debug-info-assignment-tracking", i1 true}
+  !7 = !{!"clang version 19.0.0git (git at github.com:slinder1/llvm-project.git a32b7199f0c15ea1c6c9490b6166c019c9d4bd2b)"}
+  !8 = distinct !DISubprogram(name: "func", scope: !1, file: !1, line: 1, type: !9, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !12)
+  !9 = !DISubroutineType(types: !10)
+  !10 = !{!11, !11}
+  !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+  !12 = !{!13, !14, !15}
+  !13 = !DILocalVariable(name: "arg", arg: 1, scope: !8, file: !1, line: 1, type: !11)
+  !14 = !DILocalVariable(name: "purelocal", scope: !8, file: !1, line: 1, type: !11)
+  !15 = !DILocalVariable(name: "pinnedlocal", scope: !8, file: !1, line: 1, type: !11)
+  !16 = distinct !DIAssignID()
+  !17 = !DILocation(line: 0, scope: !8)
+  !18 = !DILocation(line: 1, column: 64, scope: !8)
+  !19 = !DILocation(line: 1, column: 70, scope: !8)
+  !20 = !DILocation(line: 1, column: 92, scope: !8)
+  !21 = !DILocation(line: 1, column: 74, scope: !8)
+  !22 = !{!23, !23, i64 0}
+  !23 = !{!"int", !24, i64 0}
+  !24 = !{!"omnipotent char", !25, i64 0}
+  !25 = !{!"Simple C/C++ TBAA"}
+  !26 = distinct !DIAssignID()
+  !27 = !DILocation(line: 1, column: 105, scope: !8)
+  !28 = !DILocation(line: 1, column: 103, scope: !8)
+  !29 = !{!30, !30, i64 0}
+  !30 = !{!"long long", !24, i64 0}
+  !31 = !DILocation(line: 1, column: 148, scope: !8)
+  !32 = !DILocation(line: 1, column: 130, scope: !8)
+
+...
+---
+name:            func
+alignment:       16
+exposesReturnsTwice: false
+legalized:       false
+regBankSelected: false
+selected:        false
+failedISel:      false
+tracksRegLiveness: true
+hasWinCFI:       false
+callsEHReturn:   false
+callsUnwindInit: false
+hasEHCatchret:   false
+hasEHScopes:     false
+hasEHFunclets:   false
+isOutlined:      false
+debugInstrRef:   true
+failsVerification: false
+tracksDebugUserValues: false
+registers:
+  - { id: 0, class: gr32, preferred-register: '' }
+  - { id: 1, class: gr32, preferred-register: '' }
+  - { id: 2, class: gr64, preferred-register: '' }
+  - { id: 3, class: gr64, preferred-register: '' }
+liveins:
+  - { reg: '$edi', virtual-reg: '%0' }
+frameInfo:
+  isFrameAddressTaken: false
+  isReturnAddressTaken: false
+  hasStackMap:     false
+  hasPatchPoint:   false
+  stackSize:       0
+  offsetAdjustment: 0
+  maxAlignment:    4
+  adjustsStack:    false
+  hasCalls:        false
+  stackProtector:  ''
+  functionContext: ''
+  maxCallFrameSize: 4294967295
+  cvBytesOfCalleeSavedRegisters: 0
+  hasOpaqueSPAdjustment: false
+  hasVAStart:      false
+  hasMustTailInVarArgFunc: false
+  hasTailCall:     false
+  isCalleeSavedInfoValid: false
+  localFrameSize:  0
+  savePoint:       ''
+  restorePoint:    ''
+fixedStack:      []
+stack:
+  - { id: 0, name: pinnedlocal, type: default, offset: 0, size: 4, alignment: 4,
+      stack-id: default, callee-saved-register: '', callee-saved-restored: true,
+      debug-info-variable: '!15', debug-info-expression: '!DIExpression()',
+      debug-info-location: '!17' }
+entry_values:    []
+callSites:       []
+debugValueSubstitutions: []
+constants:       []
+machineFunctionInfo:
+  amxProgModel:    None
+body:             |
+  bb.0.entry:
+    liveins: $edi
+
+    ; CHECK-LABEL: name: func
+    ; CHECK: debug-info-expression: '!DIExpression()',
+    ; CHECK: liveins: $edi
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: DBG_VALUE $edi, $noreg, !13, !DIExpression(), debug-location !17
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:gr32 = COPY $edi
+    ; CHECK-NEXT: [[IMUL32rri:%[0-9]+]]:gr32 = nsw IMUL32rri [[COPY]], 42, implicit-def dead $eflags, debug-instr-number 1, debug-location !18
+    ; CHECK-NEXT: DBG_INSTR_REF !14, !DIExpression(DW_OP_LLVM_arg, 0), dbg-instr-ref(1, 0), debug-location !17
+    ; CHECK-NEXT: LIFETIME_START %stack.0.pinnedlocal, debug-location !19
+    ; CHECK-NEXT: [[MOV64rm:%[0-9]+]]:gr64 = MOV64rm $rip, 1, $noreg, target-flags(x86-gotpcrel) @sink, $noreg, debug-location !28 :: (load (s64) from got)
+    ; CHECK-NEXT: [[LEA64r:%[0-9]+]]:gr64 = LEA64r %stack.0.pinnedlocal, 1, $noreg, 0, $noreg
+    ; CHECK-NEXT: MOV64mr killed [[MOV64rm]], 1, $noreg, 0, $noreg, killed [[LEA64r]], debug-location !28 :: (store (s64) into @sink, !tbaa !29)
+    ; CHECK-NEXT: LIFETIME_END %stack.0.pinnedlocal, debug-location !31
+    ; CHECK-NEXT: $eax = COPY [[IMUL32rri]], debug-location !32
+    ; CHECK-NEXT: RET 0, $eax, debug-location !32
+    DBG_VALUE $edi, $noreg, !13, !DIExpression(), debug-location !17
+    %0:gr32 = COPY $edi
+    %1:gr32 = nsw IMUL32rri %0, 42, implicit-def dead $eflags, debug-instr-number 1, debug-location !18
+    DBG_INSTR_REF !14, !DIExpression(DW_OP_LLVM_arg, 0), dbg-instr-ref(1, 0), debug-location !17
+    LIFETIME_START %stack.0.pinnedlocal, debug-location !19
+    %2:gr64 = MOV64rm $rip, 1, $noreg, target-flags(x86-gotpcrel) @sink, $noreg, debug-location !28 :: (load (s64) from got)
+    %3:gr64 = LEA64r %stack.0.pinnedlocal, 1, $noreg, 0, $noreg
+    MOV64mr killed %2, 1, $noreg, 0, $noreg, killed %3, debug-location !28 :: (store (s64) into @sink, !tbaa !29)
+    LIFETIME_END %stack.0.pinnedlocal, debug-location !31
+    $eax = COPY %1, debug-location !32
+    RET 0, $eax, debug-location !32
+
+...

>From e56ae029391783d2c505d0953b067394918fe787 Mon Sep 17 00:00:00 2001
From: Scott Linder <Scott.Linder at amd.com>
Date: Tue, 25 Jun 2024 17:40:33 +0000
Subject: [PATCH 2/2] [MIR] Replace bespoke DIExpression parser

Resolve FIXME by using the LLParser implementation of parseDIExpression
from the MIParser.
---
 llvm/include/llvm/AsmParser/LLParser.h        |  3 ++
 llvm/include/llvm/AsmParser/Parser.h          |  5 ++
 llvm/lib/AsmParser/LLParser.cpp               | 19 ++++++-
 llvm/lib/AsmParser/Parser.cpp                 | 17 +++++++
 llvm/lib/CodeGen/MIRParser/MIParser.cpp       | 50 +++----------------
 .../CodeGen/MIR/Generic/diexpression-err.mir  |  2 +-
 llvm/unittests/AsmParser/AsmParserTest.cpp    | 46 +++++++++++++++++
 7 files changed, 97 insertions(+), 45 deletions(-)

diff --git a/llvm/include/llvm/AsmParser/LLParser.h b/llvm/include/llvm/AsmParser/LLParser.h
index 2b08fcc7f16a0..1e93fc0f8cc7d 100644
--- a/llvm/include/llvm/AsmParser/LLParser.h
+++ b/llvm/include/llvm/AsmParser/LLParser.h
@@ -201,6 +201,9 @@ namespace llvm {
     bool parseTypeAtBeginning(Type *&Ty, unsigned &Read,
                               const SlotMapping *Slots);
 
+    bool parseDIExpressionAtBeginning(MDNode *&Result, unsigned &Read,
+                                      const SlotMapping *Slots);
+
     LLVMContext &getContext() { return Context; }
 
   private:
diff --git a/llvm/include/llvm/AsmParser/Parser.h b/llvm/include/llvm/AsmParser/Parser.h
index b3adfd7fd76cf..01193a0240b83 100644
--- a/llvm/include/llvm/AsmParser/Parser.h
+++ b/llvm/include/llvm/AsmParser/Parser.h
@@ -21,6 +21,7 @@
 namespace llvm {
 
 class Constant;
+class DIExpression;
 class LLVMContext;
 class MemoryBufferRef;
 class Module;
@@ -202,6 +203,10 @@ Type *parseType(StringRef Asm, SMDiagnostic &Err, const Module &M,
 Type *parseTypeAtBeginning(StringRef Asm, unsigned &Read, SMDiagnostic &Err,
                            const Module &M, const SlotMapping *Slots = nullptr);
 
+DIExpression *parseDIExpressionAtBeginning(StringRef Asm, unsigned &Read,
+                                           SMDiagnostic &Err, const Module &M,
+                                           const SlotMapping *Slots);
+
 } // End llvm namespace
 
 #endif
diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp
index 21d386097fc63..7486afc05a3c0 100644
--- a/llvm/lib/AsmParser/LLParser.cpp
+++ b/llvm/lib/AsmParser/LLParser.cpp
@@ -124,6 +124,21 @@ bool LLParser::parseTypeAtBeginning(Type *&Ty, unsigned &Read,
   return false;
 }
 
+bool LLParser::parseDIExpressionAtBeginning(MDNode *&Result, unsigned &Read,
+                                            const SlotMapping *Slots) {
+  restoreParsingState(Slots);
+  Lex.Lex();
+
+  Read = 0;
+  SMLoc Start = Lex.getLoc();
+  Result = nullptr;
+  bool Status = parseDIExpression(Result, /*IsDistinct=*/false);
+  SMLoc End = Lex.getLoc();
+  Read = End.getPointer() - Start.getPointer();
+
+  return Status;
+}
+
 void LLParser::restoreParsingState(const SlotMapping *Slots) {
   if (!Slots)
     return;
@@ -5827,8 +5842,8 @@ bool LLParser::parseDILabel(MDNode *&Result, bool IsDistinct) {
 /// parseDIExpression:
 ///   ::= !DIExpression(0, 7, -1)
 bool LLParser::parseDIExpression(MDNode *&Result, bool IsDistinct) {
-  assert(Lex.getKind() == lltok::MetadataVar && "Expected metadata type name");
-  Lex.Lex();
+  if (Lex.getKind() == lltok::MetadataVar)
+    Lex.Lex();
 
   if (parseToken(lltok::lparen, "expected '(' here"))
     return true;
diff --git a/llvm/lib/AsmParser/Parser.cpp b/llvm/lib/AsmParser/Parser.cpp
index eded892f358a8..17bdec3a090e7 100644
--- a/llvm/lib/AsmParser/Parser.cpp
+++ b/llvm/lib/AsmParser/Parser.cpp
@@ -12,6 +12,7 @@
 
 #include "llvm/AsmParser/Parser.h"
 #include "llvm/AsmParser/LLParser.h"
+#include "llvm/IR/DebugInfoMetadata.h"
 #include "llvm/IR/Module.h"
 #include "llvm/IR/ModuleSummaryIndex.h"
 #include "llvm/Support/MemoryBuffer.h"
@@ -224,3 +225,19 @@ Type *llvm::parseTypeAtBeginning(StringRef Asm, unsigned &Read,
     return nullptr;
   return Ty;
 }
+
+DIExpression *llvm::parseDIExpressionAtBeginning(StringRef Asm, unsigned &Read,
+                                                 SMDiagnostic &Err,
+                                                 const Module &M,
+                                                 const SlotMapping *Slots) {
+  SourceMgr SM;
+  std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(Asm);
+  SM.AddNewSourceBuffer(std::move(Buf), SMLoc());
+  MDNode *MD;
+  if (LLParser(Asm, SM, Err, const_cast<Module *>(&M), nullptr, M.getContext())
+          .parseDIExpressionAtBeginning(MD, Read, Slots))
+    return nullptr;
+  if (auto *Expr = dyn_cast<DIExpression>(MD))
+    return Expr;
+  return nullptr;
+}
diff --git a/llvm/lib/CodeGen/MIRParser/MIParser.cpp b/llvm/lib/CodeGen/MIRParser/MIParser.cpp
index 1a12eefc8675b..188d6c9bbcf15 100644
--- a/llvm/lib/CodeGen/MIRParser/MIParser.cpp
+++ b/llvm/lib/CodeGen/MIRParser/MIParser.cpp
@@ -2302,48 +2302,14 @@ bool MIParser::parseMDNode(MDNode *&Node) {
 }
 
 bool MIParser::parseDIExpression(MDNode *&Expr) {
-  assert(Token.is(MIToken::md_diexpr));
-  lex();
-
-  // FIXME: Share this parsing with the IL parser.
-  SmallVector<uint64_t, 8> Elements;
-
-  if (expectAndConsume(MIToken::lparen))
-    return true;
-
-  if (Token.isNot(MIToken::rparen)) {
-    do {
-      if (Token.is(MIToken::Identifier)) {
-        if (unsigned Op = dwarf::getOperationEncoding(Token.stringValue())) {
-          lex();
-          Elements.push_back(Op);
-          continue;
-        }
-        if (unsigned Enc = dwarf::getAttributeEncoding(Token.stringValue())) {
-          lex();
-          Elements.push_back(Enc);
-          continue;
-        }
-        return error(Twine("invalid DWARF op '") + Token.stringValue() + "'");
-      }
-
-      if (Token.isNot(MIToken::IntegerLiteral) ||
-          Token.integerValue().isSigned())
-        return error("expected unsigned integer");
-
-      auto &U = Token.integerValue();
-      if (U.ugt(UINT64_MAX))
-        return error("element too large, limit is " + Twine(UINT64_MAX));
-      Elements.push_back(U.getZExtValue());
-      lex();
-
-    } while (consumeIfPresent(MIToken::comma));
-  }
-
-  if (expectAndConsume(MIToken::rparen))
-    return true;
-
-  Expr = DIExpression::get(MF.getFunction().getContext(), Elements);
+  unsigned Read;
+  Expr = llvm::parseDIExpressionAtBeginning(CurrentSource, Read, Error,
+                                            *PFS.MF.getFunction().getParent(),
+                                            &PFS.IRSlots);
+  CurrentSource = CurrentSource.slice(Read, StringRef::npos);
+  lex();
+  if (!Expr)
+    return error(Error.getMessage());
   return false;
 }
 
diff --git a/llvm/test/CodeGen/MIR/Generic/diexpression-err.mir b/llvm/test/CodeGen/MIR/Generic/diexpression-err.mir
index 394c0d5d48eaa..f5c81411ede90 100644
--- a/llvm/test/CodeGen/MIR/Generic/diexpression-err.mir
+++ b/llvm/test/CodeGen/MIR/Generic/diexpression-err.mir
@@ -139,7 +139,7 @@ body:             |
     DBG_VALUE $edi, $noreg, !13, !DIExpression(), debug-location !17
     %0:gr32 = COPY $edi
     %1:gr32 = nsw IMUL32rri %0, 42, implicit-def dead $eflags, debug-instr-number 1, debug-location !18
-    ; CHECK: {{.*}}.mir:[[#@LINE+1]]:38: invalid DWARF op 'W_OP_LLVM_arg'
+    ; CHECK: {{.*}}.mir:[[#@LINE+1]]:38: expected unsigned integer
     DBG_INSTR_REF !14, !DIExpression(W_OP_LLVM_arg, 0), dbg-instr-ref(1, 0), debug-location !17
     LIFETIME_START %stack.0.pinnedlocal, debug-location !19
     %2:gr64 = MOV64rm $rip, 1, $noreg, target-flags(x86-gotpcrel) @sink, $noreg, debug-location !28 :: (load (s64) from got)
diff --git a/llvm/unittests/AsmParser/AsmParserTest.cpp b/llvm/unittests/AsmParser/AsmParserTest.cpp
index f296848ed665f..3749714fd4677 100644
--- a/llvm/unittests/AsmParser/AsmParserTest.cpp
+++ b/llvm/unittests/AsmParser/AsmParserTest.cpp
@@ -11,6 +11,7 @@
 #include "llvm/AsmParser/SlotMapping.h"
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/DataLayout.h"
+#include "llvm/IR/DebugInfoMetadata.h"
 #include "llvm/IR/LLVMContext.h"
 #include "llvm/IR/Module.h"
 #include "llvm/Support/Error.h"
@@ -411,4 +412,49 @@ TEST(AsmParserTest, InvalidDataLayoutStringCallback) {
   EXPECT_EQ(Mod2->getDataLayout(), FixedDL);
 }
 
+TEST(AsmParserTest, DIExpressionAtBeginningWithSlotMappingParsing) {
+  LLVMContext Ctx;
+  SMDiagnostic Error;
+  StringRef Source =
+      "%st = type { i32, i32 }\n"
+      "@v = common global [50 x %st] zeroinitializer, align 16\n"
+      "%0 = type { i32, i32, i32, i32 }\n"
+      "@g = common global [50 x %0] zeroinitializer, align 16\n"
+      "define void @marker4(i64 %d) {\n"
+      "entry:\n"
+      "  %conv = trunc i64 %d to i32\n"
+      "  store i32 %conv, ptr getelementptr inbounds "
+      "    ([50 x %st], ptr @v, i64 0, i64 0, i32 0), align 16\n"
+      "  store i32 %conv, ptr getelementptr inbounds "
+      "    ([50 x %0], ptr @g, i64 0, i64 0, i32 0), align 16\n"
+      "  ret void\n"
+      "}";
+  SlotMapping Mapping;
+  auto Mod = parseAssemblyString(Source, Error, Ctx, &Mapping);
+  ASSERT_TRUE(Mod != nullptr);
+  auto &M = *Mod;
+  unsigned Read;
+
+  DIExpression *Expr;
+
+  Expr = parseDIExpressionAtBeginning("i32", Read, Error, M, &Mapping);
+  ASSERT_FALSE(Expr);
+
+  Expr = parseDIExpressionAtBeginning("!DIExpression()", Read, Error, M, &Mapping);
+  ASSERT_TRUE(Expr);
+  ASSERT_EQ(Expr->getNumElements(), 0);
+
+  Expr = parseDIExpressionAtBeginning("!DIExpression(0)", Read, Error, M, &Mapping);
+  ASSERT_TRUE(Expr);
+  ASSERT_EQ(Expr->getNumElements(), 1);
+
+  Expr = parseDIExpressionAtBeginning("!DIExpression(DW_OP_LLVM_fragment, 0, 1)", Read, Error, M, &Mapping);
+  ASSERT_TRUE(Expr);
+  ASSERT_EQ(Expr->getNumElements(), 3);
+
+  Expr = parseDIExpressionAtBeginning("(DW_OP_LLVM_fragment, 0, 1)", Read, Error, M, &Mapping);
+  ASSERT_TRUE(Expr);
+  ASSERT_EQ(Expr->getNumElements(), 3);
+}
+
 } // end anonymous namespace



More information about the llvm-commits mailing list