Index: llvm/lib/Transforms/Utils/PromoteMemoryToRegister.cpp =================================================================== --- llvm/lib/Transforms/Utils/PromoteMemoryToRegister.cpp +++ llvm/lib/Transforms/Utils/PromoteMemoryToRegister.cpp @@ -187,13 +187,14 @@ /// This code only looks at accesses to allocas. static bool isInterestingInstruction(const Instruction *I) { return (isa(I) && isa(I->getOperand(0))) || + (isa(I)) || (isa(I) && isa(I->getOperand(1))); } /// Get or calculate the index of the specified instruction. unsigned getInstructionIndex(const Instruction *I) { assert(isInterestingInstruction(I) && - "Not a load/store to/from an alloca?"); + "Not a dbg.value or load/store to/from an alloca?"); // If we already have this instruction number, return it. DenseMap::iterator It = InstNumbers.find(I); @@ -432,6 +433,39 @@ DII->eraseFromParent(); } } + + if (AI->getModule()->getDwarfVersion() >= 5) { + SmallVector DbgUsers; + AI->findDbgUsers(DbgUsers); + for (auto *DII : DbgUsers) { + if (!isa(DII)) + continue; + DIBuilder DIB(*AI->getModule(), /*AllowUnresolved*/ false); + auto *DIVar = DII->getVariable(); + auto *DIExpr = DII->getExpression(); + SmallVector Ops; + DIExpression::expr_op_iterator Itr = DIExpr->expr_op_begin(); + DIExpression::expr_op_iterator EndItr = DIExpr->expr_op_end(); + if (Itr != EndItr && Itr->getOp() == dwarf::DW_OP_deref) + Itr++; + else + Ops.push_back(dwarf::DW_OP_LLVM_implicit_pointer); + for (; Itr != EndItr; Itr++) { + Itr->appendToVector(Ops); + } + DIExpr = DIExpression::get(DIExpr->getContext(), Ops); + Value *DV = Info.OnlyStore->getValueOperand(); + DebugLoc DeclareLoc = DII->getDebugLoc(); + MDNode *Scope = DeclareLoc.getScope(); + DILocation *InlinedAt = DeclareLoc.getInlinedAt(); + DebugLoc NewLoc = DebugLoc::get(0, 0, Scope, InlinedAt); + + DIB.insertDbgValueIntrinsic(DV, DIVar, DIExpr, NewLoc, DII); + DII->eraseFromParent(); + LBI.deleteValue(DII); + } + } + // Remove the (now dead) store and alloca. Info.OnlyStore->eraseFromParent(); LBI.deleteValue(Info.OnlyStore); @@ -521,6 +555,113 @@ LBI.deleteValue(LI); } + if (AI->getModule()->getDwarfVersion() >= 5) { + StoresByIndex.clear(); + LBI.clear(); + + for (User *U : AI->users()) + if (StoreInst *SI = dyn_cast(U)) + StoresByIndex.push_back( + std::make_pair(LBI.getInstructionIndex(SI), SI)); + + llvm::sort(StoresByIndex, less_first()); + + using DbgValueByIndexTy = + SmallVector, 64>; + DbgValueByIndexTy DbgValueByIndex; + + for (Instruction &I : *(AI->getParent())) + if (DbgValueInst *DVI = dyn_cast(&I)) + DbgValueByIndex.push_back( + std::make_pair(LBI.getInstructionIndex(DVI), DVI)); + + llvm::sort(DbgValueByIndex, less_first()); + + for (auto User : DbgValueByIndex) { + DbgValueInst *DI = User.second; + + if (AI != DI->getValue()) + continue; + + unsigned Idx = LBI.getInstructionIndex(DI); + // Find the nearest store that has a lower index than DI. + StoresByIndexTy::iterator I = llvm::lower_bound( + StoresByIndex, std::make_pair(Idx, static_cast(nullptr)), + less_first()); + if (I == StoresByIndex.begin()) { +#if 0 // do nothing + if (StoresByIndex.empty()) + // If there are no stores, the load takes the undef value. + DI->replaceAllUsesWith(UndefValue::get(LI->getType())); + else + // There is no store before this load, bail out (load may be affected + // by the following stores - see main comment). + return false; +#endif + } else { + // Otherwise, there was a store before this load, the load takes its + // value. Note, if the load was marked as nonnull we don't want to lose + // that information when we erase it. So we preserve it with an assume. + Value *ReplVal = std::prev(I)->second->getOperand(0); +#if 0 + if (AC && LI->getMetadata(LLVMContext::MD_nonnull) && + !isKnownNonZero(ReplVal, DL, 0, AC, LI, &DT)) + addAssumeNonNull(AC, LI); + + // If the replacement value is the load, this must occur in unreachable + // code. + if (ReplVal == LI) + ReplVal = UndefValue::get(LI->getType()); +#endif + DIBuilder DIB(*AI->getModule(), /*AllowUnresolved*/ false); + auto *DIVar = DI->getVariable(); + auto *DIExpr = DI->getExpression(); + SmallVector Ops; + DIExpression::expr_op_iterator Itr = DIExpr->expr_op_begin(); + DIExpression::expr_op_iterator EndItr = DIExpr->expr_op_end(); + if (Itr != EndItr && Itr->getOp() == dwarf::DW_OP_deref) + Itr++; + else + Ops.push_back(dwarf::DW_OP_LLVM_implicit_pointer); + for (; Itr != EndItr; Itr++) { + Itr->appendToVector(Ops); + } + DIExpr = DIExpression::get(DIExpr->getContext(), Ops); + DebugLoc DeclareLoc = DI->getDebugLoc(); + MDNode *Scope = DeclareLoc.getScope(); + DILocation *InlinedAt = DeclareLoc.getInlinedAt(); + DebugLoc NewLoc = DebugLoc::get(0, 0, Scope, InlinedAt); + DIB.insertDbgValueIntrinsic(ReplVal, DIVar, DIExpr, NewLoc, DI); + + DbgValueByIndexTy::iterator Iter = llvm::lower_bound( + DbgValueByIndex, + std::make_pair(Idx, static_cast(nullptr)), + less_first()); + + StoresByIndexTy::iterator EI = StoresByIndex.end(); + while (++Iter != DbgValueByIndex.end()) { + if (DI->getOperand(1) == Iter->second->getOperand(1)) { + EI = llvm::lower_bound( + StoresByIndex, + std::make_pair(Iter->first, static_cast(nullptr)), + less_first()); + break; + } + } + + DI->eraseFromParent(); + LBI.deleteValue(DI); + + while (I != EI) { + ReplVal = I->second->getOperand(0); + DIB.insertDbgValueIntrinsic(ReplVal, DIVar, DIExpr, + I->second->getDebugLoc(), I->second); + I++; + } + } + } + } + // Remove the (now dead) stores and alloca. while (!AI->use_empty()) { StoreInst *SI = cast(AI->user_back()); Index: llvm/test/DebugInfo/X86/dwarfdump-implicit_pointer_instcomb.c =================================================================== --- /dev/null +++ llvm/test/DebugInfo/X86/dwarfdump-implicit_pointer_instcomb.c @@ -0,0 +1,28 @@ +// RUN: clang %s -O2 -gdwarf-5 -o %t.o +// RUN: llvm-dwarfdump %t.o | FileCheck %s + +// CHECK-LABEL: DW_AT_name ("__implicit_ptr_tmp_0") +// CHECK-LABEL: DW_TAG_variable +// CHECK-NEXT: DW_AT_location +// CHECK-NEXT: DW_OP_implicit_pointer {{0x.+}} +0 + +// CHECK-LABEL: DW_TAG_formal_parameter +// CHECK-NEXT: DW_AT_location +// CHECK-NEXT: DW_OP_implicit_pointer {{0x.+}} +0 +// CHECK-NEXT: "ptr" + +volatile int gvar = 7; + +int func(int *ptr) { + gvar = *ptr; + return *ptr + 5; +} + +int main() { + int var = 4; + int *ptrVar = &var; + + int res = func(ptrVar); + + return res; +} Index: llvm/test/DebugInfo/X86/implicit_pointer_instcomb.c =================================================================== --- /dev/null +++ llvm/test/DebugInfo/X86/implicit_pointer_instcomb.c @@ -0,0 +1,24 @@ +// RUN: clang %s -O2 -gdwarf-5 -S -emit-llvm -o %t.ll +// RUN: FileCheck %s --input-file=%t.ll + +volatile int gvar = 7; + +int func(int *ptr) { + gvar = *ptr; + return *ptr + 5; +} + +int main() { + int var = 4; + int *ptrVar = &var; + + // CHECK: call void @llvm.dbg.value(metadata i32 4, metadata [[MD2:!.*]], metadata !DIExpression()) + // CHECK: call void @llvm.dbg.value(metadata i32 4, metadata [[MD1:!.*]], metadata !DIExpression(DW_OP_LLVM_implicit_pointer)) + // CHECK: call void @llvm.dbg.value(metadata i32 4, metadata [[MD3:!.*]], metadata !DIExpression(DW_OP_LLVM_implicit_pointer)) + int res = func(ptrVar); + + return res; +} +// CHECK: [[MD3]] = !DILocalVariable(name: "ptr" +// CHECK: [[MD2]] = !DILocalVariable(name: "var" +// CHECK: [[MD1]] = !DILocalVariable(name: "ptrVar" Index: llvm/test/DebugInfo/X86/implicit_pointer_promote2reg.c =================================================================== --- /dev/null +++ llvm/test/DebugInfo/X86/implicit_pointer_promote2reg.c @@ -0,0 +1,32 @@ +// RUN: clang %s -O2 -gdwarf-5 -S -emit-llvm -o %t.ll +// RUN: FileCheck %s --input-file=%t.ll + +static const char *b = "opq"; +volatile int v; +int main() { + int var1 = 4; + int var2 = 5; + int arr1[2] = {2, 3}; + int *ptr1; + int *ptr2 = 0; + int **ptrptr1; + int **ptrptr2 = 0; + + v++; + ptr1 = &var1; + ptr2 = &var2; + // CHECK: call void @llvm.dbg.value(metadata i32 4, metadata [[MD1:!.+]], metadata !DIExpression(DW_OP_LLVM_implicit_pointer)) + // CHECK: call void @llvm.dbg.value(metadata i32 5, metadata [[MD2:!.+]], metadata !DIExpression(DW_OP_LLVM_implicit_pointer)) + ptrptr1 = &ptr1; + ptrptr2 = &ptr2; + // CHECK: call void @llvm.dbg.value(metadata i32 4, metadata [[MD3:!.+]], metadata !DIExpression(DW_OP_LLVM_implicit_pointer, DW_OP_LLVM_implicit_pointer)) + // CHECK: call void @llvm.dbg.value(metadata i32 5, metadata [[MD4:!.+]], metadata !DIExpression(DW_OP_LLVM_implicit_pointer, DW_OP_LLVM_implicit_pointer)) + + v++; + + return arr1[0] + arr1[1] + *ptr1 + *ptr2 + **ptrptr1 + **ptrptr2 - 5; +} +// CHECK: [[MD1]] = !DILocalVariable(name: "ptr1" +// CHECK: [[MD2]] = !DILocalVariable(name: "ptr2" +// CHECK: [[MD3]] = !DILocalVariable(name: "ptrptr1" +// CHECK: [[MD4]] = !DILocalVariable(name: "ptrptr2" Index: llvm/test/DebugInfo/X86/implicit_pointer_temp_reference.cc =================================================================== --- /dev/null +++ llvm/test/DebugInfo/X86/implicit_pointer_temp_reference.cc @@ -0,0 +1,16 @@ +// RUN: clang %s -O2 -gdwarf-5 -S -emit-llvm -o %t.ll +// RUN: FileCheck %s --input-file=%t.ll + +__attribute__((optnone)) int source() { + return 3; +} +__attribute__((optnone)) void f(int i) { +} +inline void sink(const int &p) { + f(p); +} +int main() { + // CHECK: call void @llvm.dbg.value(metadata i32 3, metadata [[MD:!.+]], metadata !DIExpression(DW_OP_LLVM_implicit_pointer)) + sink(source()); +} +// CHECK: [[MD]] = !DILocalVariable(name: "p"