Index: llvm/lib/Transforms/IPO/IROutliner.cpp =================================================================== --- llvm/lib/Transforms/IPO/IROutliner.cpp +++ llvm/lib/Transforms/IPO/IROutliner.cpp @@ -16,8 +16,9 @@ #include "llvm/Analysis/OptimizationRemarkEmitter.h" #include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/IR/Attributes.h" -#include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DIBuilder.h" +#include "llvm/IR/DebugInfo.h" +#include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/Mangler.h" #include "llvm/IR/PassManager.h" @@ -666,6 +667,18 @@ if (!isa(&Val)) { // Remove the debug information for outlined functions. Val.setDebugLoc(DebugLoc()); + + // Loop info metadata may contain line locations. Update them to have no + // value in the new subprogram since the outlined code could be from + // several locations. + auto updateLoopInfoLoc = [&New](Metadata *MD) -> Metadata * { + if (DISubprogram *SP = New.getSubprogram()) + if (auto *Loc = dyn_cast_or_null(MD)) + return DILocation::get(New.getContext(), Loc->getLine(), + Loc->getColumn(), SP, nullptr); + return MD; + }; + updateLoopMetadataDebugLocations(Val, updateLoopInfoLoc); continue; } Index: llvm/test/Transforms/IROutliner/outlining-strip-loop-info.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/IROutliner/outlining-strip-loop-info.ll @@ -0,0 +1,191 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --include-generated-funcs +; RUN: opt -S -verify -iroutliner -ir-outlining-no-cost < %s | FileCheck %s + +; Make sure that we strip loop debug info from instructions that are outlined as +; well as regular debug info. + +target triple = "arm64-apple-unknown" + +%struct.hoge = type { %struct.widget, i32, i32, [4 x i8] } +%struct.widget = type <{ i32 (...)**, %struct.quux*, i32, [4 x i8], %struct.hoge.0*, %struct.hoge.0*, i32 }> +%struct.quux = type { i32 (...)** } +%struct.hoge.0 = type { i32, i32, i32, i32, i8*, %struct.quux* } +%struct.barney = type <{ i32 (...)**, %struct.quux*, i32, [4 x i8], %struct.hoge.0*, %struct.hoge.0*, i32, [4 x i8] }> + +define void @ham(%struct.hoge* nocapture noundef nonnull readonly align 8 dereferenceable(52) %arg, %struct.hoge.0* noundef nonnull align 8 dereferenceable(32) %arg1) unnamed_addr #0 align 2 !dbg !1 { +bb: + br i1 undef, label %bb2, label %bb21 + +bb2: ; preds = %bb + %var = load i32, i32* undef, align 8 + %var3 = icmp ult i32 %var, 65 + br i1 %var3, label %bb10, label %bb4 + +bb4: ; preds = %bb2 + %var5 = getelementptr inbounds %struct.hoge.0, %struct.hoge.0* %arg1, i64 0, i32 1 + %var6 = load i32, i32* %var5, align 4 + %var7 = icmp eq i32 %var6, 0 + br i1 %var7, label %bb22, label %bb8 + +bb8: ; preds = %bb4 + %var9 = getelementptr inbounds %struct.hoge.0, %struct.hoge.0* %arg1, i64 0, i32 4 + br label %bb13 + +bb10: ; preds = %bb2 + %var11 = getelementptr inbounds %struct.hoge.0, %struct.hoge.0* %arg1, i64 0, i32 2 + %var12 = bitcast i32* %var11 to <2 x i32>* + store <2 x i32> zeroinitializer, <2 x i32>* %var12, align 8 + br label %bb22 + +bb13: ; preds = %bb13, %bb8 + %var14 = phi i64 [ 0, %bb8 ], [ %var17, %bb13 ] + %var15 = load i8*, i8** %var9, align 8 + %var16 = getelementptr inbounds i8, i8* %var15, i64 %var14 + store i8 0, i8* %var16, align 1 + %var17 = add nuw nsw i64 %var14, 1 + %var18 = load i32, i32* %var5, align 4 + %var19 = zext i32 %var18 to i64 + %var20 = icmp ult i64 %var17, %var19 + br i1 %var20, label %bb13, label %bb22, !dbg !7, !llvm.loop !11 + +bb21: ; preds = %bb + unreachable + +bb22: ; preds = %bb13, %bb10, %bb4 + ret void +} + +; Function Attrs: optsize ssp uwtable +define void @wombat(%struct.hoge* nocapture noundef nonnull readonly align 8 dereferenceable(52) %arg, %struct.hoge.0* noundef nonnull align 8 dereferenceable(32) %arg1) unnamed_addr #0 align 2 !dbg !13 { +bb: + br i1 undef, label %bb2, label %bb21 + +bb2: ; preds = %bb + %var = load i32, i32* undef, align 8 + %var3 = icmp ult i32 %var, 65 + br i1 %var3, label %bb10, label %bb4 + +bb4: ; preds = %bb2 + %var5 = getelementptr inbounds %struct.hoge.0, %struct.hoge.0* %arg1, i64 0, i32 1 + %var6 = load i32, i32* %var5, align 4 + %var7 = icmp eq i32 %var6, 0 + br i1 %var7, label %bb22, label %bb8 + +bb8: ; preds = %bb4 + %var9 = getelementptr inbounds %struct.hoge.0, %struct.hoge.0* %arg1, i64 0, i32 4 + br label %bb13 + +bb10: ; preds = %bb2 + %var11 = getelementptr inbounds %struct.hoge.0, %struct.hoge.0* %arg1, i64 0, i32 2 + %var12 = bitcast i32* %var11 to <2 x i32>* + store <2 x i32> zeroinitializer, <2 x i32>* %var12, align 8 + br label %bb22 + +bb13: ; preds = %bb13, %bb8 + %var14 = phi i64 [ 0, %bb8 ], [ %var17, %bb13 ] + %var15 = load i8*, i8** %var9, align 8 + %var16 = getelementptr inbounds i8, i8* %var15, i64 %var14 + store i8 0, i8* %var16, align 1 + %var17 = add nuw nsw i64 %var14, 1 + %var18 = load i32, i32* %var5, align 4 + %var19 = zext i32 %var18 to i64 + %var20 = icmp ult i64 %var17, %var19 + br i1 %var20, label %bb13, label %bb22 + +bb21: ; preds = %bb + unreachable + +bb22: ; preds = %bb13, %bb10, %bb4 + ret void +} + +; Function Attrs: inlinehint nounwind optsize ssp uwtable +define linkonce_odr void @foo(%struct.barney* noundef nonnull align 8 dereferenceable(44) %arg) unnamed_addr #1 align 2 !dbg !14 { +bb: + unreachable +} + +attributes #0 = { optsize ssp uwtable } +attributes #1 = { inlinehint nounwind optsize ssp uwtable } + +!llvm.module.flags = !{!0} +!llvm.dbg.cu = !{} + +!0 = !{i32 2, !"Debug Info Version", i32 3} +!1 = distinct !DISubprogram(name: "pluto", scope: !2, file: !2, line: 160, type: !3, scopeLine: 161, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !5) +!2 = !DIFile(filename: "file", directory: "dir") +!3 = !DISubroutineType(types: !4) +!4 = !{} +!5 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !6, producer: "ver", isOptimized: true, runtimeVersion: 0, emissionKind: LineTablesOnly, splitDebugInlining: false, nameTableKind: None, sysroot: "sysroot", sdk: "sdk") +!6 = !DIFile(filename: "file", directory: "dir") +!7 = !DILocation(line: 354, column: 13, scope: !8, inlinedAt: !10) +!8 = distinct !DISubprogram(name: "baz", scope: !9, file: !9, line: 345, type: !3, scopeLine: 346, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !5) +!9 = !DIFile(filename: "file", directory: "dir") +!10 = distinct !DILocation(line: 164, column: 15, scope: !1) +!11 = distinct !{!11, !7, !12} +!12 = !DILocation(line: 355, column: 37, scope: !8, inlinedAt: !10) +!13 = distinct !DISubprogram(name: "foo", scope: !2, file: !2, line: 172, type: !3, scopeLine: 173, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !5) +!14 = distinct !DISubprogram(name: "bar", scope: !15, file: !15, line: 219, type: !3, scopeLine: 220, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !5) +!15 = !DIFile(filename: "file", directory: "dir") +; CHECK-LABEL: @ham( +; CHECK-NEXT: bb: +; CHECK-NEXT: br i1 undef, label [[BB2:%.*]], label [[BB21:%.*]] +; CHECK: bb2: +; CHECK-NEXT: call void @outlined_ir_func_0(%struct.hoge.0* [[ARG1:%.*]]), !dbg [[DBG6:![0-9]+]] +; CHECK-NEXT: br label [[BB22:%.*]] +; CHECK: bb21: +; CHECK-NEXT: unreachable +; CHECK: bb22: +; CHECK-NEXT: ret void +; +; +; CHECK-LABEL: @wombat( +; CHECK-NEXT: bb: +; CHECK-NEXT: br i1 undef, label [[BB2:%.*]], label [[BB21:%.*]] +; CHECK: bb2: +; CHECK-NEXT: call void @outlined_ir_func_0(%struct.hoge.0* [[ARG1:%.*]]), !dbg [[DBG10:![0-9]+]] +; CHECK-NEXT: br label [[BB22:%.*]] +; CHECK: bb21: +; CHECK-NEXT: unreachable +; CHECK: bb22: +; CHECK-NEXT: ret void +; +; +; CHECK-LABEL: @foo( +; CHECK-NEXT: bb: +; CHECK-NEXT: unreachable +; +; +; CHECK-LABEL: define internal void @outlined_ir_func_0( +; CHECK-NEXT: newFuncRoot: +; CHECK-NEXT: br label [[BB2_TO_OUTLINE:%.*]] +; CHECK: bb2_to_outline: +; CHECK-NEXT: [[VAR:%.*]] = load i32, i32* undef, align 8 +; CHECK-NEXT: [[VAR3:%.*]] = icmp ult i32 [[VAR]], 65 +; CHECK-NEXT: br i1 [[VAR3]], label [[BB10:%.*]], label [[BB4:%.*]] +; CHECK: bb4: +; CHECK-NEXT: [[VAR5:%.*]] = getelementptr inbounds [[STRUCT_HOGE_0:%.*]], %struct.hoge.0* [[TMP0:%.*]], i64 0, i32 1 +; CHECK-NEXT: [[VAR6:%.*]] = load i32, i32* [[VAR5]], align 4 +; CHECK-NEXT: [[VAR7:%.*]] = icmp eq i32 [[VAR6]], 0 +; CHECK-NEXT: br i1 [[VAR7]], label [[BB22_EXITSTUB:%.*]], label [[BB8:%.*]] +; CHECK: bb8: +; CHECK-NEXT: [[VAR9:%.*]] = getelementptr inbounds [[STRUCT_HOGE_0]], %struct.hoge.0* [[TMP0]], i64 0, i32 4 +; CHECK-NEXT: br label [[BB13:%.*]] +; CHECK: bb10: +; CHECK-NEXT: [[VAR11:%.*]] = getelementptr inbounds [[STRUCT_HOGE_0]], %struct.hoge.0* [[TMP0]], i64 0, i32 2 +; CHECK-NEXT: [[VAR12:%.*]] = bitcast i32* [[VAR11]] to <2 x i32>* +; CHECK-NEXT: store <2 x i32> zeroinitializer, <2 x i32>* [[VAR12]], align 8 +; CHECK-NEXT: br label [[BB22_EXITSTUB]] +; CHECK: bb13: +; CHECK-NEXT: [[VAR14:%.*]] = phi i64 [ 0, [[BB8]] ], [ [[VAR17:%.*]], [[BB13]] ] +; CHECK-NEXT: [[VAR15:%.*]] = load i8*, i8** [[VAR9]], align 8 +; CHECK-NEXT: [[VAR16:%.*]] = getelementptr inbounds i8, i8* [[VAR15]], i64 [[VAR14]] +; CHECK-NEXT: store i8 0, i8* [[VAR16]], align 1 +; CHECK-NEXT: [[VAR17]] = add nuw nsw i64 [[VAR14]], 1 +; CHECK-NEXT: [[VAR18:%.*]] = load i32, i32* [[VAR5]], align 4 +; CHECK-NEXT: [[VAR19:%.*]] = zext i32 [[VAR18]] to i64 +; CHECK-NEXT: [[VAR20:%.*]] = icmp ult i64 [[VAR17]], [[VAR19]] +; CHECK-NEXT: br i1 [[VAR20]], label [[BB13]], label [[BB22_EXITSTUB]], !llvm.loop [[LOOP13:![0-9]+]] +; CHECK: bb22.exitStub: +; CHECK-NEXT: ret void +;