Index: lib/Transforms/Utils/Local.cpp =================================================================== --- lib/Transforms/Utils/Local.cpp +++ lib/Transforms/Utils/Local.cpp @@ -1596,6 +1596,45 @@ DII->setOperand(2, MetadataAsValue::get(I.getContext(), DIExpr)); DEBUG(dbgs() << "SALVAGE: " << *DII << '\n'); } + } else if (auto *EVI = dyn_cast(&I)) { + // An extractvalue instruction indexes into an aggregate value using one + // or more indices. Rewrite the extractvalue by calculating the offset of + // the desired value within the aggregate and shifting the aggregate by + // that many bits. This is safe because the debug info records the size of + // the desired value: excess high bits of the aggregate are discarded. E.g: + // + // struct { int32_t x, y, z } s; + // s.y => extractvalue s, 1 => s >> 32 + // + // We handle nested aggregates by summing up the offsets to sub-aggregates, + // one at a time, until each index in the extractvalue is accounted for. + Value *Agg = EVI->getAggregateOperand(); + ArrayRef Indices = EVI->getIndices(); + unsigned FieldOffset = 0; + for (unsigned Depth = 0, E = Indices.size(); Depth < E; ++Depth) { + ArrayRef IndicesForSubAgg = Indices.take_front(Depth); + Type *IndexedTy = + ExtractValueInst::getIndexedType(Agg->getType(), IndicesForSubAgg); + if (IndexedTy->isStructTy()) { + auto *Layout = DL.getStructLayout(cast(IndexedTy)); + FieldOffset += Layout->getElementOffsetInBits(Indices[Depth]); + } else if (IndexedTy->isArrayTy()) { + Type *ElementTy = IndexedTy->getSequentialElementType(); + FieldOffset += DL.getTypeAllocSizeInBits(ElementTy) * Indices[Depth]; + } else { + llvm_unreachable("Not a valid type to index into with extractvalue"); + } + } + + MetadataAsValue *AggMD = wrapMD(Agg); + for (auto *DII : DbgUsers) { + if (FieldOffset) { + applyOps(DII, {dwarf::DW_OP_constu, FieldOffset, dwarf::DW_OP_shr}); + } else { + DII->setOperand(0, AggMD); + DEBUG(dbgs() << "SALVAGE: " << *DII << '\n'); + } + } } } Index: test/Transforms/InstCombine/debuginfo-variables.ll =================================================================== --- test/Transforms/InstCombine/debuginfo-variables.ll +++ test/Transforms/InstCombine/debuginfo-variables.ll @@ -93,3 +93,66 @@ %1 = and i64 %A, 256 ret void } + +define void @test_extractvalue_1([1 x i64] %Arr) { +; CHECK-LABEL: @test_extractvalue_1( +; CHECK-NEXT: call void @llvm.dbg.value(metadata [1 x i64] %Arr, metadata !77, metadata !DIExpression()), !dbg !78 + %1 = extractvalue [1 x i64] %Arr, 0 + ret void +} + +define void @test_extractvalue_2([2 x i64] %Arr) { +; CHECK-LABEL: @test_extractvalue_2( +; CHECK-NEXT: call void @llvm.dbg.value(metadata [2 x i64] %Arr, metadata !82, metadata !DIExpression(DW_OP_constu, 64, DW_OP_shr, DW_OP_stack_value)), !dbg !83 + %1 = extractvalue [2 x i64] %Arr, 1 + ret void +} + +%ty1 = type { i32 } + +define void @test_extractvalue_3(%ty1 %S) { +; CHECK-LABEL: @test_extractvalue_3( +; CHECK-NEXT: call void @llvm.dbg.value(metadata %ty1 %S, metadata !87, metadata !DIExpression()), !dbg !88 + %1 = extractvalue %ty1 %S, 0 + ret void +} + +; Note: this is an unpacked struct. +%ty2 = type { [2 x i8], [2 x i32], %ty1, [2 x %ty1], <2 x i8>, [1 x [2 x i8]] } + +define void @test_extractvalue_4(%ty2 %S) { +; CHECK-LABEL: @test_extractvalue_4( +; CHECK-NEXT: call void @llvm.dbg.value(metadata %ty2 %S, metadata !92, metadata !DIExpression(DW_OP_constu, 8, DW_OP_shr, DW_OP_stack_value)), !dbg !100 +; CHECK-NEXT: call void @llvm.dbg.value(metadata %ty2 %S, metadata !94, metadata !DIExpression(DW_OP_constu, 64, DW_OP_shr, DW_OP_stack_value)), !dbg !101 +; CHECK-NEXT: call void @llvm.dbg.value(metadata %ty2 %S, metadata !95, metadata !DIExpression(DW_OP_constu, 96, DW_OP_shr, DW_OP_stack_value)), !dbg !102 +; CHECK-NEXT: call void @llvm.dbg.value(metadata %ty2 %S, metadata !96, metadata !DIExpression(DW_OP_constu, 160, DW_OP_shr, DW_OP_stack_value)), !dbg !103 +; CHECK-NEXT: call void @llvm.dbg.value(metadata %ty2 %S, metadata !97, metadata !DIExpression(DW_OP_constu, 192, DW_OP_shr, DW_OP_stack_value)), !dbg !104 +; CHECK-NEXT: call void @llvm.dbg.value(metadata %ty2 %S, metadata !99, metadata !DIExpression(DW_OP_constu, 216, DW_OP_shr, DW_OP_stack_value)), !dbg !105 + %1 = extractvalue %ty2 %S, 0, 1 + %2 = extractvalue %ty2 %S, 1, 1 + %3 = extractvalue %ty2 %S, 2, 0 + %4 = extractvalue %ty2 %S, 3, 1, 0 + %5 = extractvalue %ty2 %S, 4 + %6 = extractvalue %ty2 %S, 5, 0, 1 + ret void +} + +; Note: this is a packed struct. +%ty3 = type <{ [2 x i8], [2 x i32], %ty1, [2 x %ty1], <2 x i8>, [1 x [2 x i8]] }> + +define void @test_extractvalue_5(%ty3 %S) { +; CHECK-LABEL: @test_extractvalue_5( +; CHECK-NEXT: call void @llvm.dbg.value(metadata %ty3 %S, metadata !109, metadata !DIExpression(DW_OP_constu, 8, DW_OP_shr, DW_OP_stack_value)), !dbg !115 +; CHECK-NEXT: call void @llvm.dbg.value(metadata %ty3 %S, metadata !110, metadata !DIExpression(DW_OP_constu, 48, DW_OP_shr, DW_OP_stack_value)), !dbg !116 +; CHECK-NEXT: call void @llvm.dbg.value(metadata %ty3 %S, metadata !111, metadata !DIExpression(DW_OP_constu, 80, DW_OP_shr, DW_OP_stack_value)), !dbg !117 +; CHECK-NEXT: call void @llvm.dbg.value(metadata %ty3 %S, metadata !112, metadata !DIExpression(DW_OP_constu, 144, DW_OP_shr, DW_OP_stack_value)), !dbg !118 +; CHECK-NEXT: call void @llvm.dbg.value(metadata %ty3 %S, metadata !113, metadata !DIExpression(DW_OP_constu, 176, DW_OP_shr, DW_OP_stack_value)), !dbg !119 +; CHECK-NEXT: call void @llvm.dbg.value(metadata %ty3 %S, metadata !114, metadata !DIExpression(DW_OP_constu, 200, DW_OP_shr, DW_OP_stack_value)), !dbg !120 + %1 = extractvalue %ty3 %S, 0, 1 + %2 = extractvalue %ty3 %S, 1, 1 + %3 = extractvalue %ty3 %S, 2, 0 + %4 = extractvalue %ty3 %S, 3, 1, 0 + %5 = extractvalue %ty3 %S, 4 + %6 = extractvalue %ty3 %S, 5, 0, 1 + ret void +}