[Reassociate] Do not drop debug location if replacement is missing

Summary:
When reassociating an expression, do not drop the instruction's
original debug location in case the replacement location is
missing.

The debug location must at least not be dropped for inlinable
callsites of debug-info-bearing functions in debug-info-bearing
functions. Failing to do so would result in an "inlinable function "
"call in a function with debug info must have a !dbg location"
error in the verifier.

As preserving the original debug location is not expected
to result in overly jumpy debug line information, it is
preserved for all other cases too.

This fixes PR34231:
https://bugs.llvm.org/show_bug.cgi?id=34231

Original patch by David Stenberg

Reviewers: davide, craig.topper, mcrosier, dblaikie, aprantl

Reviewed By: davide, aprantl

Subscribers: aprantl

Differential Revision: https://reviews.llvm.org/D36865

llvm-svn: 311642
diff --git a/llvm/lib/Transforms/Scalar/Reassociate.cpp b/llvm/lib/Transforms/Scalar/Reassociate.cpp
index e0ef8cf..5883244 100644
--- a/llvm/lib/Transforms/Scalar/Reassociate.cpp
+++ b/llvm/lib/Transforms/Scalar/Reassociate.cpp
@@ -2137,7 +2137,8 @@
     DEBUG(dbgs() << "Reassoc to scalar: " << *V << '\n');
     I->replaceAllUsesWith(V);
     if (Instruction *VI = dyn_cast<Instruction>(V))
-      VI->setDebugLoc(I->getDebugLoc());
+      if (I->getDebugLoc())
+        VI->setDebugLoc(I->getDebugLoc());
     RedoInsts.insert(I);
     ++NumAnnihil;
     return;
diff --git a/llvm/test/Transforms/Reassociate/keep-debug-loc.ll b/llvm/test/Transforms/Reassociate/keep-debug-loc.ll
new file mode 100644
index 0000000..1a1031f
--- /dev/null
+++ b/llvm/test/Transforms/Reassociate/keep-debug-loc.ll
@@ -0,0 +1,48 @@
+; RUN: opt -S -reassociate < %s | FileCheck %s
+
+; PR34231
+;
+; Verify that the original debug location is kept if the
+; replacement debug location is missing when
+; reassociating expressions.
+
+define i16 @fn1() !dbg !3 {
+  ret i16 undef
+}
+
+define void @fn2() !dbg !6 {
+; CHECK-LABEL: @fn2
+; CHECK: call i16 @fn1(), !dbg ![[LOC1:[0-9]+]]
+; CHECK-NOT: or i16
+  %inlinable_call = call i16 @fn1(), !dbg !7
+  %dbgless_instruction = or i16 %inlinable_call, 0
+  store i16 %dbgless_instruction, i16* undef, align 1
+  unreachable
+}
+
+define void @fn3() !dbg !8 {
+; CHECK-LABEL: @fn3
+; CHECK: load i16, i16* undef, !dbg ![[LOC2:[0-9]+]]
+; CHECK-NOT: or i16
+  %instruction = load i16, i16* undef, !dbg !9
+  %dbgless_instruction = or i16 %instruction, 0
+  store i16 %dbgless_instruction, i16* undef, align 1
+  unreachable
+}
+
+; CHECK: ![[LOC1]] = !DILocation(line: 7
+; CHECK: ![[LOC2]] = !DILocation(line: 9
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!2}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 6.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: LineTablesOnly)
+!1 = !DIFile(filename: "foo.c", directory: "/")
+!2 = !{i32 2, !"Debug Info Version", i32 3}
+!3 = distinct !DISubprogram(name: "fn1", scope: !1, file: !1, line: 2, type: !4, isLocal: false, isDefinition: true, scopeLine: 2, isOptimized: true, unit: !0)
+!4 = !DISubroutineType(types: !5)
+!5 = !{}
+!6 = distinct !DISubprogram(name: "fn2", scope: !1, file: !1, line: 3, type: !4, isLocal: false, isDefinition: true, scopeLine: 3, isOptimized: true, unit: !0)
+!7 = !DILocation(line: 7, column: 10, scope: !6)
+!8 = distinct !DISubprogram(name: "fn3", scope: !1, file: !1, line: 8, type: !4, isLocal: false, isDefinition: true, scopeLine: 3, isOptimized: true, unit: !0)
+!9 = !DILocation(line: 9, column: 10, scope: !8)