paulkirth updated this revision to Diff 469446.
paulkirth added a comment.
Code Cleanups and Test Cases
- Replace SmallVector with SmallPtrSet
- Add some comments/clarification
- Add a larger, more flexible test case
There's still room for improvement for both testing and documentation.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D135488/new/
https://reviews.llvm.org/D135488
Files:
llvm/include/llvm/CodeGen/MachineFrameInfo.h
llvm/include/llvm/CodeGen/Passes.h
llvm/include/llvm/InitializePasses.h
llvm/lib/CodeGen/CMakeLists.txt
llvm/lib/CodeGen/CodeGen.cpp
llvm/lib/CodeGen/MachineFrameInfo.cpp
llvm/lib/CodeGen/PrologEpilogInserter.cpp
llvm/lib/CodeGen/StackFramePrinterPass.cpp
llvm/lib/CodeGen/TargetPassConfig.cpp
llvm/test/CodeGen/X86/stack-frame-printer.ll
llvm/test/CodeGen/X86/stack-frame-printer2.ll
Index: llvm/test/CodeGen/X86/stack-frame-printer2.ll
===================================================================
--- /dev/null
+++ llvm/test/CodeGen/X86/stack-frame-printer2.ll
@@ -0,0 +1,764 @@
+
+; RUN: llc %s -print-stack-frame -o /dev/null --march=x86 -mcpu=i386 2>&1 | FileCheck %s --check-prefix=BOTH --check-prefix=DEBUG
+; RUN: opt %s -strip -S | llc -print-stack-frame -o /dev/null --march=x86 -mcpu=i386 2>&1 | FileCheck %s --check-prefix=BOTH --check-prefix=STRIPPED
+
+
+; BOTH: # Stack Layout: cleanup_array
+; BOTH: Offset{{.*}}Align{{.*}}Size
+; BOTH: [SP+4]{{.+}}16{{.+}}4
+; DEBUG: a @ dot.c:13
+; STRIPPED-NOT: a @ dot.c:13
+; BOTH: [SP-4]{{.+}}Spill 8{{.+}}4
+
+; BOTH: # Stack Layout: cleanup_result
+; BOTH: Offset{{.+}}Align{{.+}}Size
+; BOTH: [SP+4]{{.+}}16{{.+}}4
+; DEBUG: res @ dot.c:21
+; STRIPPED-NOT: res @ dot.c:21
+; BOTH: [SP-4]{{.+}}Spill 8{{.+}}4
+
+; BOTH: # Stack Layout: do_work
+; BOTH: Offset{{.+}}Align{{.+}}Size
+; BOTH: [SP+12]{{.+}}8{{.+}}4
+; DEBUG: out @ dot.c:32
+; STRIPPED-NOT: out @ dot.c:32
+; BOTH: [SP+8]{{.+}}4{{.+}}4
+; BOTH: [SP+4]{{.+}}16{{.+}}4
+; DEBUG: A @ dot.c:32
+; STRIPPED-NOT: A @ dot.c:32
+; BOTH: [SP-4]{{.+}}Spill 8{{.+}}4
+; BOTH: [SP-12]{{.+}}8{{.+}}4
+; DEBUG: AB @ dot.c:38
+; STRIPPED-NOT: AB @ dot.c:38
+; BOTH: [SP-16]{{.+}}4{{.+}}4
+; DEBUG: i @ dot.c:55
+; STRIPPED-NOT: i @ dot.c:55
+; BOTH: [SP-20]{{.+}}8{{.+}}4
+; DEBUG: B @ dot.c:32
+; STRIPPED-NOT: B @ dot.c:32
+; BOTH: [SP-24]{{.+}}4{{.+}}4
+; DEBUG: len @ dot.c:37
+; STRIPPED-NOT: len @ dot.c:37
+; BOTH: [SP-28]{{.+}}4{{.+}}4
+; BOTH: [SP-32]{{.+}}4{{.+}}4
+; DEBUG: sum @ dot.c:54
+; STRIPPED-NOT: sum @ dot.c:54
+
+; BOTH: # Stack Layout: gen_array
+; BOTH: Offset{{.+}}Align{{.+}}Size
+; BOTH: [SP+4]{{.+}}16{{.+}}4
+; DEBUG: size @ dot.c:62
+; STRIPPED-NOT: size @ dot.c:62
+; BOTH: [SP-4]{{.+}}Spill 8{{.+}}4
+; BOTH: [SP-12]{{.+}}8{{.+}}4
+; DEBUG: res @ dot.c:65
+; STRIPPED-NOT: res @ dot.c:65
+; BOTH: [SP-16]{{.+}}4{{.+}}4
+; DEBUG: i @ dot.c:69
+; STRIPPED-NOT: i @ dot.c:69
+; BOTH: [SP-20]{{.+}}8 4
+
+; BOTH: # Stack Layout: caller
+; BOTH: Offset{{.+}}Align{{.+}}Size
+; BOTH: [SP-4]{{.+}}Spill 8{{.+}}4
+; BOTH: [SP-12]{{.+}}8{{.+}}4
+; DEBUG: res @ dot.c:80
+; STRIPPED-NOT: res @ dot.c:80
+; BOTH: [SP-20]{{.+}}8{{.+}}4
+; DEBUG: B @ dot.c:79
+; STRIPPED-NOT: B @ dot.c:79
+; BOTH: [SP-28]{{.+}}8{{.+}}4
+; DEBUG: A @ dot.c:78
+; STRIPPED-NOT: A @ dot.c:78
+; BOTH: [SP-32]{{.+}}4{{.+}}4
+; DEBUG: ret @ dot.c:81
+; STRIPPED-NOT: ret @ dot.c:81
+; BOTH: [SP-36]{{.+}}4{{.+}}4
+; BOTH: [SP-40]{{.+}}4{{.+}}4
+; DEBUG: err @ dot.c:83
+; STRIPPED-NOT: err @ dot.c:83
+; BOTH: [SP-44]{{.+}}4{{.+}}4
+; DEBUG: size @ dot.c:77
+; STRIPPED-NOT: size @ dot.c:77
+
+
+
+
+; ModuleID = 'dot.c'
+source_filename = "dot.c"
+
+%struct.Array = type { ptr, i32 }
+%struct.Result = type { ptr, i32 }
+
+; Function Attrs: noinline nounwind uwtable
+define dso_local void @cleanup_array(ptr noundef %0) #0 !dbg !24 {
+ %2 = alloca ptr, align 8
+ store ptr %0, ptr %2, align 8
+ call void @llvm.dbg.declare(metadata ptr %2, metadata !28, metadata !DIExpression()), !dbg !29
+ %3 = load ptr, ptr %2, align 8, !dbg !30
+ %4 = icmp ne ptr %3, null, !dbg !30
+ br i1 %4, label %6, label %5, !dbg !32
+
+5: ; preds = %1
+ br label %16, !dbg !33
+
+6: ; preds = %1
+ %7 = load ptr, ptr %2, align 8, !dbg !34
+ %8 = getelementptr inbounds %struct.Array, ptr %7, i32 0, i32 0, !dbg !36
+ %9 = load ptr, ptr %8, align 8, !dbg !36
+ %10 = icmp ne ptr %9, null, !dbg !34
+ br i1 %10, label %12, label %11, !dbg !37
+
+11: ; preds = %6
+ br label %16, !dbg !38
+
+12: ; preds = %6
+ %13 = load ptr, ptr %2, align 8, !dbg !39
+ %14 = getelementptr inbounds %struct.Array, ptr %13, i32 0, i32 0, !dbg !40
+ %15 = load ptr, ptr %14, align 8, !dbg !40
+ call void @free(ptr noundef %15) #5, !dbg !41
+ br label %16, !dbg !42
+
+16: ; preds = %12, %11, %5
+ ret void, !dbg !42
+}
+
+; Function Attrs: nocallback nofree nosync nounwind readnone speculatable willreturn
+declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
+
+; Function Attrs: nounwind
+declare void @free(ptr noundef) #2
+
+; Function Attrs: noinline nounwind uwtable
+define dso_local void @cleanup_result(ptr noundef %0) #0 !dbg !43 {
+ %2 = alloca ptr, align 8
+ store ptr %0, ptr %2, align 8
+ call void @llvm.dbg.declare(metadata ptr %2, metadata !46, metadata !DIExpression()), !dbg !47
+ %3 = load ptr, ptr %2, align 8, !dbg !48
+ %4 = icmp ne ptr %3, null, !dbg !48
+ br i1 %4, label %6, label %5, !dbg !50
+
+5: ; preds = %1
+ br label %19, !dbg !51
+
+6: ; preds = %1
+ %7 = load ptr, ptr %2, align 8, !dbg !52
+ %8 = getelementptr inbounds %struct.Result, ptr %7, i32 0, i32 0, !dbg !54
+ %9 = load ptr, ptr %8, align 8, !dbg !54
+ %10 = icmp ne ptr %9, null, !dbg !52
+ br i1 %10, label %12, label %11, !dbg !55
+
+11: ; preds = %6
+ br label %19, !dbg !56
+
+12: ; preds = %6
+ %13 = load ptr, ptr %2, align 8, !dbg !57
+ %14 = getelementptr inbounds %struct.Result, ptr %13, i32 0, i32 0, !dbg !58
+ %15 = load ptr, ptr %14, align 8, !dbg !58
+ call void @cleanup_array(ptr noundef %15), !dbg !59
+ %16 = load ptr, ptr %2, align 8, !dbg !60
+ %17 = getelementptr inbounds %struct.Result, ptr %16, i32 0, i32 0, !dbg !61
+ %18 = load ptr, ptr %17, align 8, !dbg !61
+ call void @free(ptr noundef %18) #5, !dbg !62
+ br label %19, !dbg !63
+
+19: ; preds = %12, %11, %5
+ ret void, !dbg !63
+}
+
+; Function Attrs: noinline nounwind uwtable
+define dso_local i32 @do_work(ptr noundef %0, ptr noundef %1, ptr noundef %2) #0 !dbg !64 {
+ %4 = alloca i32, align 4
+ %5 = alloca ptr, align 8
+ %6 = alloca ptr, align 8
+ %7 = alloca ptr, align 8
+ %8 = alloca i32, align 4
+ %9 = alloca ptr, align 8
+ %10 = alloca i32, align 4
+ %11 = alloca i32, align 4
+ store ptr %0, ptr %5, align 8
+ call void @llvm.dbg.declare(metadata ptr %5, metadata !67, metadata !DIExpression()), !dbg !68
+ store ptr %1, ptr %6, align 8
+ call void @llvm.dbg.declare(metadata ptr %6, metadata !69, metadata !DIExpression()), !dbg !70
+ store ptr %2, ptr %7, align 8
+ call void @llvm.dbg.declare(metadata ptr %7, metadata !71, metadata !DIExpression()), !dbg !72
+ %12 = load ptr, ptr %5, align 8, !dbg !73
+ %13 = icmp ne ptr %12, null, !dbg !73
+ br i1 %13, label %14, label %17, !dbg !75
+
+14: ; preds = %3
+ %15 = load ptr, ptr %6, align 8, !dbg !76
+ %16 = icmp ne ptr %15, null, !dbg !76
+ br i1 %16, label %18, label %17, !dbg !77
+
+17: ; preds = %14, %3
+ store i32 -1, ptr %4, align 4, !dbg !78
+ br label %106, !dbg !78
+
+18: ; preds = %14
+ %19 = load ptr, ptr %5, align 8, !dbg !79
+ %20 = getelementptr inbounds %struct.Array, ptr %19, i32 0, i32 1, !dbg !81
+ %21 = load i32, ptr %20, align 8, !dbg !81
+ %22 = load ptr, ptr %6, align 8, !dbg !82
+ %23 = getelementptr inbounds %struct.Array, ptr %22, i32 0, i32 1, !dbg !83
+ %24 = load i32, ptr %23, align 8, !dbg !83
+ %25 = icmp ne i32 %21, %24, !dbg !84
+ br i1 %25, label %26, label %27, !dbg !85
+
+26: ; preds = %18
+ store i32 -1, ptr %4, align 4, !dbg !86
+ br label %106, !dbg !86
+
+27: ; preds = %18
+ call void @llvm.dbg.declare(metadata ptr %8, metadata !87, metadata !DIExpression()), !dbg !89
+ %28 = load ptr, ptr %5, align 8, !dbg !90
+ %29 = getelementptr inbounds %struct.Array, ptr %28, i32 0, i32 1, !dbg !91
+ %30 = load i32, ptr %29, align 8, !dbg !91
+ store i32 %30, ptr %8, align 4, !dbg !89
+ call void @llvm.dbg.declare(metadata ptr %9, metadata !92, metadata !DIExpression()), !dbg !93
+ %31 = load ptr, ptr %7, align 8, !dbg !94
+ %32 = getelementptr inbounds %struct.Result, ptr %31, i32 0, i32 0, !dbg !96
+ %33 = load ptr, ptr %32, align 8, !dbg !96
+ %34 = icmp eq ptr %33, null, !dbg !97
+ br i1 %34, label %35, label %44, !dbg !98
+
+35: ; preds = %27
+ %36 = call noalias ptr @malloc(i64 noundef 16) #6, !dbg !99
+ store ptr %36, ptr %9, align 8, !dbg !101
+ %37 = load ptr, ptr %9, align 8, !dbg !102
+ %38 = getelementptr inbounds %struct.Array, ptr %37, i32 0, i32 0, !dbg !103
+ store ptr null, ptr %38, align 8, !dbg !104
+ %39 = load ptr, ptr %9, align 8, !dbg !105
+ %40 = getelementptr inbounds %struct.Array, ptr %39, i32 0, i32 1, !dbg !106
+ store i32 0, ptr %40, align 8, !dbg !107
+ %41 = load ptr, ptr %9, align 8, !dbg !108
+ %42 = load ptr, ptr %7, align 8, !dbg !109
+ %43 = getelementptr inbounds %struct.Result, ptr %42, i32 0, i32 0, !dbg !110
+ store ptr %41, ptr %43, align 8, !dbg !111
+ br label %48, !dbg !112
+
+44: ; preds = %27
+ %45 = load ptr, ptr %7, align 8, !dbg !113
+ %46 = getelementptr inbounds %struct.Result, ptr %45, i32 0, i32 0, !dbg !115
+ %47 = load ptr, ptr %46, align 8, !dbg !115
+ store ptr %47, ptr %9, align 8, !dbg !116
+ br label %48
+
+48: ; preds = %44, %35
+ %49 = load ptr, ptr %9, align 8, !dbg !117
+ %50 = getelementptr inbounds %struct.Array, ptr %49, i32 0, i32 0, !dbg !119
+ %51 = load ptr, ptr %50, align 8, !dbg !119
+ %52 = icmp ne ptr %51, null, !dbg !117
+ br i1 %52, label %53, label %57, !dbg !120
+
+53: ; preds = %48
+ %54 = load ptr, ptr %9, align 8, !dbg !121
+ %55 = getelementptr inbounds %struct.Array, ptr %54, i32 0, i32 0, !dbg !122
+ %56 = load ptr, ptr %55, align 8, !dbg !122
+ call void @free(ptr noundef %56) #5, !dbg !123
+ br label %57, !dbg !123
+
+57: ; preds = %53, %48
+ %58 = load i32, ptr %8, align 4, !dbg !124
+ %59 = sext i32 %58 to i64, !dbg !124
+ %60 = mul i64 %59, 4, !dbg !125
+ %61 = call noalias ptr @malloc(i64 noundef %60) #6, !dbg !126
+ %62 = load ptr, ptr %9, align 8, !dbg !127
+ %63 = getelementptr inbounds %struct.Array, ptr %62, i32 0, i32 0, !dbg !128
+ store ptr %61, ptr %63, align 8, !dbg !129
+ %64 = load i32, ptr %8, align 4, !dbg !130
+ %65 = load ptr, ptr %9, align 8, !dbg !131
+ %66 = getelementptr inbounds %struct.Array, ptr %65, i32 0, i32 1, !dbg !132
+ store i32 %64, ptr %66, align 8, !dbg !133
+ call void @llvm.dbg.declare(metadata ptr %10, metadata !134, metadata !DIExpression()), !dbg !135
+ store i32 0, ptr %10, align 4, !dbg !135
+ call void @llvm.dbg.declare(metadata ptr %11, metadata !136, metadata !DIExpression()), !dbg !138
+ store i32 0, ptr %11, align 4, !dbg !138
+ br label %67, !dbg !139
+
+67: ; preds = %102, %57
+ %68 = load i32, ptr %11, align 4, !dbg !140
+ %69 = load i32, ptr %8, align 4, !dbg !142
+ %70 = icmp slt i32 %68, %69, !dbg !143
+ br i1 %70, label %71, label %105, !dbg !144
+
+71: ; preds = %67
+ %72 = load ptr, ptr %5, align 8, !dbg !145
+ %73 = getelementptr inbounds %struct.Array, ptr %72, i32 0, i32 0, !dbg !147
+ %74 = load ptr, ptr %73, align 8, !dbg !147
+ %75 = load i32, ptr %11, align 4, !dbg !148
+ %76 = sext i32 %75 to i64, !dbg !145
+ %77 = getelementptr inbounds i32, ptr %74, i64 %76, !dbg !145
+ %78 = load i32, ptr %77, align 4, !dbg !145
+ %79 = load ptr, ptr %6, align 8, !dbg !149
+ %80 = getelementptr inbounds %struct.Array, ptr %79, i32 0, i32 0, !dbg !150
+ %81 = load ptr, ptr %80, align 8, !dbg !150
+ %82 = load i32, ptr %11, align 4, !dbg !151
+ %83 = sext i32 %82 to i64, !dbg !149
+ %84 = getelementptr inbounds i32, ptr %81, i64 %83, !dbg !149
+ %85 = load i32, ptr %84, align 4, !dbg !149
+ %86 = mul nsw i32 %78, %85, !dbg !152
+ %87 = load ptr, ptr %9, align 8, !dbg !153
+ %88 = getelementptr inbounds %struct.Array, ptr %87, i32 0, i32 0, !dbg !154
+ %89 = load ptr, ptr %88, align 8, !dbg !154
+ %90 = load i32, ptr %11, align 4, !dbg !155
+ %91 = sext i32 %90 to i64, !dbg !153
+ %92 = getelementptr inbounds i32, ptr %89, i64 %91, !dbg !153
+ store i32 %86, ptr %92, align 4, !dbg !156
+ %93 = load ptr, ptr %9, align 8, !dbg !157
+ %94 = getelementptr inbounds %struct.Array, ptr %93, i32 0, i32 0, !dbg !158
+ %95 = load ptr, ptr %94, align 8, !dbg !158
+ %96 = load i32, ptr %11, align 4, !dbg !159
+ %97 = sext i32 %96 to i64, !dbg !157
+ %98 = getelementptr inbounds i32, ptr %95, i64 %97, !dbg !157
+ %99 = load i32, ptr %98, align 4, !dbg !157
+ %100 = load i32, ptr %10, align 4, !dbg !160
+ %101 = add nsw i32 %100, %99, !dbg !160
+ store i32 %101, ptr %10, align 4, !dbg !160
+ br label %102, !dbg !161
+
+102: ; preds = %71
+ %103 = load i32, ptr %11, align 4, !dbg !162
+ %104 = add nsw i32 %103, 1, !dbg !162
+ store i32 %104, ptr %11, align 4, !dbg !162
+ br label %67, !dbg !163, !llvm.loop !164
+
+105: ; preds = %67
+ store i32 0, ptr %4, align 4, !dbg !167
+ br label %106, !dbg !167
+
+106: ; preds = %105, %26, %17
+ %107 = load i32, ptr %4, align 4, !dbg !168
+ ret i32 %107, !dbg !168
+}
+
+; Function Attrs: nounwind allocsize(0)
+declare noalias ptr @malloc(i64 noundef) #3
+
+; Function Attrs: noinline nounwind uwtable
+define dso_local ptr @gen_array(i32 noundef %0) #0 !dbg !169 {
+ %2 = alloca ptr, align 8
+ %3 = alloca i32, align 4
+ %4 = alloca ptr, align 8
+ %5 = alloca i32, align 4
+ store i32 %0, ptr %3, align 4
+ call void @llvm.dbg.declare(metadata ptr %3, metadata !172, metadata !DIExpression()), !dbg !173
+ %6 = load i32, ptr %3, align 4, !dbg !174
+ %7 = icmp slt i32 %6, 0, !dbg !176
+ br i1 %7, label %8, label %9, !dbg !177
+
+8: ; preds = %1
+ store ptr null, ptr %2, align 8, !dbg !178
+ br label %37, !dbg !178
+
+9: ; preds = %1
+ call void @llvm.dbg.declare(metadata ptr %4, metadata !179, metadata !DIExpression()), !dbg !180
+ %10 = call noalias ptr @malloc(i64 noundef 16) #6, !dbg !181
+ store ptr %10, ptr %4, align 8, !dbg !180
+ %11 = load i32, ptr %3, align 4, !dbg !182
+ %12 = load ptr, ptr %4, align 8, !dbg !183
+ %13 = getelementptr inbounds %struct.Array, ptr %12, i32 0, i32 1, !dbg !184
+ store i32 %11, ptr %13, align 8, !dbg !185
+ %14 = load i32, ptr %3, align 4, !dbg !186
+ %15 = sext i32 %14 to i64, !dbg !186
+ %16 = mul i64 %15, 4, !dbg !187
+ %17 = call noalias ptr @malloc(i64 noundef %16) #6, !dbg !188
+ %18 = load ptr, ptr %4, align 8, !dbg !189
+ %19 = getelementptr inbounds %struct.Array, ptr %18, i32 0, i32 0, !dbg !190
+ store ptr %17, ptr %19, align 8, !dbg !191
+ call void @llvm.dbg.declare(metadata ptr %5, metadata !192, metadata !DIExpression()), !dbg !194
+ store i32 0, ptr %5, align 4, !dbg !194
+ br label %20, !dbg !195
+
+20: ; preds = %32, %9
+ %21 = load i32, ptr %5, align 4, !dbg !196
+ %22 = load i32, ptr %3, align 4, !dbg !198
+ %23 = icmp slt i32 %21, %22, !dbg !199
+ br i1 %23, label %24, label %35, !dbg !200
+
+24: ; preds = %20
+ %25 = call i32 @rand() #5, !dbg !201
+ %26 = load ptr, ptr %4, align 8, !dbg !203
+ %27 = getelementptr inbounds %struct.Array, ptr %26, i32 0, i32 0, !dbg !204
+ %28 = load ptr, ptr %27, align 8, !dbg !204
+ %29 = load i32, ptr %5, align 4, !dbg !205
+ %30 = sext i32 %29 to i64, !dbg !203
+ %31 = getelementptr inbounds i32, ptr %28, i64 %30, !dbg !203
+ store i32 %25, ptr %31, align 4, !dbg !206
+ br label %32, !dbg !207
+
+32: ; preds = %24
+ %33 = load i32, ptr %5, align 4, !dbg !208
+ %34 = add nsw i32 %33, 1, !dbg !208
+ store i32 %34, ptr %5, align 4, !dbg !208
+ br label %20, !dbg !209, !llvm.loop !210
+
+35: ; preds = %20
+ %36 = load ptr, ptr %4, align 8, !dbg !212
+ store ptr %36, ptr %2, align 8, !dbg !213
+ br label %37, !dbg !213
+
+37: ; preds = %35, %8
+ %38 = load ptr, ptr %2, align 8, !dbg !214
+ ret ptr %38, !dbg !214
+}
+
+; Function Attrs: nounwind
+declare i32 @rand() #2
+
+; Function Attrs: noinline nounwind uwtable
+define dso_local i32 @caller() #0 !dbg !215 {
+ %1 = alloca i32, align 4
+ %2 = alloca i32, align 4
+ %3 = alloca ptr, align 8
+ %4 = alloca ptr, align 8
+ %5 = alloca ptr, align 8
+ %6 = alloca i32, align 4
+ %7 = alloca i32, align 4
+ call void @llvm.dbg.declare(metadata ptr %2, metadata !218, metadata !DIExpression()), !dbg !219
+ store i32 100, ptr %2, align 4, !dbg !219
+ call void @llvm.dbg.declare(metadata ptr %3, metadata !220, metadata !DIExpression()), !dbg !221
+ %8 = call ptr @gen_array(i32 noundef 100), !dbg !222
+ store ptr %8, ptr %3, align 8, !dbg !221
+ call void @llvm.dbg.declare(metadata ptr %4, metadata !223, metadata !DIExpression()), !dbg !224
+ %9 = call ptr @gen_array(i32 noundef 100), !dbg !225
+ store ptr %9, ptr %4, align 8, !dbg !224
+ call void @llvm.dbg.declare(metadata ptr %5, metadata !226, metadata !DIExpression()), !dbg !227
+ %10 = call noalias ptr @malloc(i64 noundef 16) #6, !dbg !228
+ store ptr %10, ptr %5, align 8, !dbg !227
+ call void @llvm.dbg.declare(metadata ptr %6, metadata !229, metadata !DIExpression()), !dbg !230
+ store i32 -1, ptr %6, align 4, !dbg !230
+ call void @llvm.dbg.declare(metadata ptr %7, metadata !231, metadata !DIExpression()), !dbg !232
+ %11 = load ptr, ptr %3, align 8, !dbg !233
+ %12 = load ptr, ptr %4, align 8, !dbg !234
+ %13 = load ptr, ptr %5, align 8, !dbg !235
+ %14 = call i32 @do_work(ptr noundef %11, ptr noundef %12, ptr noundef %13), !dbg !236
+ store i32 %14, ptr %7, align 4, !dbg !232
+ %15 = load i32, ptr %7, align 4, !dbg !237
+ %16 = icmp eq i32 %15, -1, !dbg !239
+ br i1 %16, label %17, label %18, !dbg !240
+
+17: ; preds = %0
+ br label %30, !dbg !241
+
+18: ; preds = %0
+ %19 = load ptr, ptr %5, align 8, !dbg !243
+ %20 = getelementptr inbounds %struct.Result, ptr %19, i32 0, i32 1, !dbg !244
+ %21 = load i32, ptr %20, align 8, !dbg !244
+ store i32 %21, ptr %6, align 4, !dbg !245
+ %22 = load i32, ptr %6, align 4, !dbg !246
+ %23 = icmp eq i32 %22, -1, !dbg !248
+ br i1 %23, label %24, label %26, !dbg !249
+
+24: ; preds = %18
+ %25 = call i32 @caller(), !dbg !250
+ store i32 %25, ptr %1, align 4, !dbg !251
+ br label %35, !dbg !251
+
+26: ; preds = %18
+ %27 = load ptr, ptr %5, align 8, !dbg !252
+ %28 = getelementptr inbounds %struct.Result, ptr %27, i32 0, i32 0, !dbg !253
+ %29 = load ptr, ptr %28, align 8, !dbg !253
+ call void @use_dot_vector(ptr noundef %29), !dbg !254
+ br label %30, !dbg !254
+
+30: ; preds = %26, %17
+ call void @llvm.dbg.label(metadata !255), !dbg !256
+ %31 = load ptr, ptr %3, align 8, !dbg !257
+ call void @cleanup_array(ptr noundef %31), !dbg !258
+ %32 = load ptr, ptr %4, align 8, !dbg !259
+ call void @cleanup_array(ptr noundef %32), !dbg !260
+ %33 = load ptr, ptr %5, align 8, !dbg !261
+ call void @cleanup_result(ptr noundef %33), !dbg !262
+ %34 = load i32, ptr %6, align 4, !dbg !263
+ store i32 %34, ptr %1, align 4, !dbg !264
+ br label %35, !dbg !264
+
+35: ; preds = %30, %24
+ %36 = load i32, ptr %1, align 4, !dbg !265
+ ret i32 %36, !dbg !265
+}
+
+declare void @use_dot_vector(ptr noundef) #4
+
+; Function Attrs: nocallback nofree nosync nounwind readnone speculatable willreturn
+declare void @llvm.dbg.label(metadata) #1
+
+attributes #0 = { noinline nounwind uwtable "frame-pointer"="all" }
+attributes #1 = { nocallback nofree nosync nounwind readnone speculatable willreturn }
+attributes #2 = { nounwind "frame-pointer"="all" }
+attributes #3 = { nounwind allocsize(0) "frame-pointer"="all" }
+attributes #4 = { "frame-pointer"="all" }
+attributes #5 = { nounwind }
+attributes #6 = { nounwind allocsize(0) }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!16, !17, !18, !19, !20, !21, !22}
+!llvm.ident = !{!23}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "Fuchsia clang version 16.0.0 (https://llvm.googlesource.com/llvm-project f85c1f3b7c0bda64aef12201e2f5bbad6028582d)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, retainedTypes: !2, splitDebugInlining: false, nameTableKind: None)
+!1 = !DIFile(filename: "dot.c", directory: "/usr/local/google/home/paulkirth/test/stack-frame-dump", checksumkind: CSK_MD5, checksum: "bd8ba1fe67914c5427978672a19a51d2")
+!2 = !{!3, !4, !8, !11}
+!3 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64)
+!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64)
+!5 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Array", file: !1, line: 3, size: 128, elements: !6)
+!6 = !{!7, !10}
+!7 = !DIDerivedType(tag: DW_TAG_member, name: "data", scope: !5, file: !1, line: 4, baseType: !8, size: 64)
+!8 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !9, size: 64)
+!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!10 = !DIDerivedType(tag: DW_TAG_member, name: "size", scope: !5, file: !1, line: 5, baseType: !9, size: 32, offset: 64)
+!11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !12, size: 64)
+!12 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Result", file: !1, line: 8, size: 128, elements: !13)
+!13 = !{!14, !15}
+!14 = !DIDerivedType(tag: DW_TAG_member, name: "data", scope: !12, file: !1, line: 9, baseType: !4, size: 64)
+!15 = !DIDerivedType(tag: DW_TAG_member, name: "sum", scope: !12, file: !1, line: 10, baseType: !9, size: 32, offset: 64)
+!16 = !{i32 7, !"Dwarf Version", i32 5}
+!17 = !{i32 2, !"Debug Info Version", i32 3}
+!18 = !{i32 1, !"wchar_size", i32 4}
+!19 = !{i32 8, !"PIC Level", i32 2}
+!20 = !{i32 7, !"PIE Level", i32 2}
+!21 = !{i32 7, !"uwtable", i32 2}
+!22 = !{i32 7, !"frame-pointer", i32 2}
+!23 = !{!"Fuchsia clang version 16.0.0 (https://llvm.googlesource.com/llvm-project f85c1f3b7c0bda64aef12201e2f5bbad6028582d)"}
+!24 = distinct !DISubprogram(name: "cleanup_array", scope: !1, file: !1, line: 13, type: !25, scopeLine: 13, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !27)
+!25 = !DISubroutineType(types: !26)
+!26 = !{null, !4}
+!27 = !{}
+!28 = !DILocalVariable(name: "a", arg: 1, scope: !24, file: !1, line: 13, type: !4)
+!29 = !DILocation(line: 13, column: 34, scope: !24)
+!30 = !DILocation(line: 14, column: 8, scope: !31)
+!31 = distinct !DILexicalBlock(scope: !24, file: !1, line: 14, column: 7)
+!32 = !DILocation(line: 14, column: 7, scope: !24)
+!33 = !DILocation(line: 15, column: 5, scope: !31)
+!34 = !DILocation(line: 16, column: 8, scope: !35)
+!35 = distinct !DILexicalBlock(scope: !24, file: !1, line: 16, column: 7)
+!36 = !DILocation(line: 16, column: 11, scope: !35)
+!37 = !DILocation(line: 16, column: 7, scope: !24)
+!38 = !DILocation(line: 17, column: 5, scope: !35)
+!39 = !DILocation(line: 18, column: 8, scope: !24)
+!40 = !DILocation(line: 18, column: 11, scope: !24)
+!41 = !DILocation(line: 18, column: 3, scope: !24)
+!42 = !DILocation(line: 19, column: 1, scope: !24)
+!43 = distinct !DISubprogram(name: "cleanup_result", scope: !1, file: !1, line: 21, type: !44, scopeLine: 21, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !27)
+!44 = !DISubroutineType(types: !45)
+!45 = !{null, !11}
+!46 = !DILocalVariable(name: "res", arg: 1, scope: !43, file: !1, line: 21, type: !11)
+!47 = !DILocation(line: 21, column: 36, scope: !43)
+!48 = !DILocation(line: 22, column: 8, scope: !49)
+!49 = distinct !DILexicalBlock(scope: !43, file: !1, line: 22, column: 7)
+!50 = !DILocation(line: 22, column: 7, scope: !43)
+!51 = !DILocation(line: 23, column: 5, scope: !49)
+!52 = !DILocation(line: 24, column: 8, scope: !53)
+!53 = distinct !DILexicalBlock(scope: !43, file: !1, line: 24, column: 7)
+!54 = !DILocation(line: 24, column: 13, scope: !53)
+!55 = !DILocation(line: 24, column: 7, scope: !43)
+!56 = !DILocation(line: 25, column: 5, scope: !53)
+!57 = !DILocation(line: 26, column: 17, scope: !43)
+!58 = !DILocation(line: 26, column: 22, scope: !43)
+!59 = !DILocation(line: 26, column: 3, scope: !43)
+!60 = !DILocation(line: 27, column: 8, scope: !43)
+!61 = !DILocation(line: 27, column: 13, scope: !43)
+!62 = !DILocation(line: 27, column: 3, scope: !43)
+!63 = !DILocation(line: 28, column: 1, scope: !43)
+!64 = distinct !DISubprogram(name: "do_work", scope: !1, file: !1, line: 32, type: !65, scopeLine: 32, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !27)
+!65 = !DISubroutineType(types: !66)
+!66 = !{!9, !4, !4, !11}
+!67 = !DILocalVariable(name: "A", arg: 1, scope: !64, file: !1, line: 32, type: !4)
+!68 = !DILocation(line: 32, column: 27, scope: !64)
+!69 = !DILocalVariable(name: "B", arg: 2, scope: !64, file: !1, line: 32, type: !4)
+!70 = !DILocation(line: 32, column: 44, scope: !64)
+!71 = !DILocalVariable(name: "out", arg: 3, scope: !64, file: !1, line: 32, type: !11)
+!72 = !DILocation(line: 32, column: 62, scope: !64)
+!73 = !DILocation(line: 33, column: 8, scope: !74)
+!74 = distinct !DILexicalBlock(scope: !64, file: !1, line: 33, column: 7)
+!75 = !DILocation(line: 33, column: 10, scope: !74)
+!76 = !DILocation(line: 33, column: 14, scope: !74)
+!77 = !DILocation(line: 33, column: 7, scope: !64)
+!78 = !DILocation(line: 34, column: 5, scope: !74)
+!79 = !DILocation(line: 35, column: 7, scope: !80)
+!80 = distinct !DILexicalBlock(scope: !64, file: !1, line: 35, column: 7)
+!81 = !DILocation(line: 35, column: 10, scope: !80)
+!82 = !DILocation(line: 35, column: 18, scope: !80)
+!83 = !DILocation(line: 35, column: 21, scope: !80)
+!84 = !DILocation(line: 35, column: 15, scope: !80)
+!85 = !DILocation(line: 35, column: 7, scope: !64)
+!86 = !DILocation(line: 36, column: 5, scope: !80)
+!87 = !DILocalVariable(name: "len", scope: !64, file: !1, line: 37, type: !88)
+!88 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !9)
+!89 = !DILocation(line: 37, column: 13, scope: !64)
+!90 = !DILocation(line: 37, column: 19, scope: !64)
+!91 = !DILocation(line: 37, column: 22, scope: !64)
+!92 = !DILocalVariable(name: "AB", scope: !64, file: !1, line: 38, type: !4)
+!93 = !DILocation(line: 38, column: 17, scope: !64)
+!94 = !DILocation(line: 39, column: 7, scope: !95)
+!95 = distinct !DILexicalBlock(scope: !64, file: !1, line: 39, column: 7)
+!96 = !DILocation(line: 39, column: 12, scope: !95)
+!97 = !DILocation(line: 39, column: 17, scope: !95)
+!98 = !DILocation(line: 39, column: 7, scope: !64)
+!99 = !DILocation(line: 40, column: 26, scope: !100)
+!100 = distinct !DILexicalBlock(scope: !95, file: !1, line: 39, column: 26)
+!101 = !DILocation(line: 40, column: 8, scope: !100)
+!102 = !DILocation(line: 41, column: 5, scope: !100)
+!103 = !DILocation(line: 41, column: 9, scope: !100)
+!104 = !DILocation(line: 41, column: 14, scope: !100)
+!105 = !DILocation(line: 42, column: 5, scope: !100)
+!106 = !DILocation(line: 42, column: 9, scope: !100)
+!107 = !DILocation(line: 42, column: 14, scope: !100)
+!108 = !DILocation(line: 43, column: 17, scope: !100)
+!109 = !DILocation(line: 43, column: 5, scope: !100)
+!110 = !DILocation(line: 43, column: 10, scope: !100)
+!111 = !DILocation(line: 43, column: 15, scope: !100)
+!112 = !DILocation(line: 44, column: 3, scope: !100)
+!113 = !DILocation(line: 45, column: 10, scope: !114)
+!114 = distinct !DILexicalBlock(scope: !95, file: !1, line: 44, column: 10)
+!115 = !DILocation(line: 45, column: 15, scope: !114)
+!116 = !DILocation(line: 45, column: 8, scope: !114)
+!117 = !DILocation(line: 48, column: 7, scope: !118)
+!118 = distinct !DILexicalBlock(scope: !64, file: !1, line: 48, column: 7)
+!119 = !DILocation(line: 48, column: 11, scope: !118)
+!120 = !DILocation(line: 48, column: 7, scope: !64)
+!121 = !DILocation(line: 49, column: 10, scope: !118)
+!122 = !DILocation(line: 49, column: 14, scope: !118)
+!123 = !DILocation(line: 49, column: 5, scope: !118)
+!124 = !DILocation(line: 51, column: 28, scope: !64)
+!125 = !DILocation(line: 51, column: 32, scope: !64)
+!126 = !DILocation(line: 51, column: 21, scope: !64)
+!127 = !DILocation(line: 51, column: 3, scope: !64)
+!128 = !DILocation(line: 51, column: 7, scope: !64)
+!129 = !DILocation(line: 51, column: 12, scope: !64)
+!130 = !DILocation(line: 52, column: 14, scope: !64)
+!131 = !DILocation(line: 52, column: 3, scope: !64)
+!132 = !DILocation(line: 52, column: 7, scope: !64)
+!133 = !DILocation(line: 52, column: 12, scope: !64)
+!134 = !DILocalVariable(name: "sum", scope: !64, file: !1, line: 54, type: !9)
+!135 = !DILocation(line: 54, column: 7, scope: !64)
+!136 = !DILocalVariable(name: "i", scope: !137, file: !1, line: 55, type: !9)
+!137 = distinct !DILexicalBlock(scope: !64, file: !1, line: 55, column: 3)
+!138 = !DILocation(line: 55, column: 12, scope: !137)
+!139 = !DILocation(line: 55, column: 8, scope: !137)
+!140 = !DILocation(line: 55, column: 19, scope: !141)
+!141 = distinct !DILexicalBlock(scope: !137, file: !1, line: 55, column: 3)
+!142 = !DILocation(line: 55, column: 23, scope: !141)
+!143 = !DILocation(line: 55, column: 21, scope: !141)
+!144 = !DILocation(line: 55, column: 3, scope: !137)
+!145 = !DILocation(line: 56, column: 19, scope: !146)
+!146 = distinct !DILexicalBlock(scope: !141, file: !1, line: 55, column: 33)
+!147 = !DILocation(line: 56, column: 22, scope: !146)
+!148 = !DILocation(line: 56, column: 27, scope: !146)
+!149 = !DILocation(line: 56, column: 32, scope: !146)
+!150 = !DILocation(line: 56, column: 35, scope: !146)
+!151 = !DILocation(line: 56, column: 40, scope: !146)
+!152 = !DILocation(line: 56, column: 30, scope: !146)
+!153 = !DILocation(line: 56, column: 5, scope: !146)
+!154 = !DILocation(line: 56, column: 9, scope: !146)
+!155 = !DILocation(line: 56, column: 14, scope: !146)
+!156 = !DILocation(line: 56, column: 17, scope: !146)
+!157 = !DILocation(line: 57, column: 12, scope: !146)
+!158 = !DILocation(line: 57, column: 16, scope: !146)
+!159 = !DILocation(line: 57, column: 21, scope: !146)
+!160 = !DILocation(line: 57, column: 9, scope: !146)
+!161 = !DILocation(line: 58, column: 3, scope: !146)
+!162 = !DILocation(line: 55, column: 28, scope: !141)
+!163 = !DILocation(line: 55, column: 3, scope: !141)
+!164 = distinct !{!164, !144, !165, !166}
+!165 = !DILocation(line: 58, column: 3, scope: !137)
+!166 = !{!"llvm.loop.mustprogress"}
+!167 = !DILocation(line: 59, column: 3, scope: !64)
+!168 = !DILocation(line: 60, column: 1, scope: !64)
+!169 = distinct !DISubprogram(name: "gen_array", scope: !1, file: !1, line: 62, type: !170, scopeLine: 62, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !27)
+!170 = !DISubroutineType(types: !171)
+!171 = !{!4, !9}
+!172 = !DILocalVariable(name: "size", arg: 1, scope: !169, file: !1, line: 62, type: !9)
+!173 = !DILocation(line: 62, column: 29, scope: !169)
+!174 = !DILocation(line: 63, column: 7, scope: !175)
+!175 = distinct !DILexicalBlock(scope: !169, file: !1, line: 63, column: 7)
+!176 = !DILocation(line: 63, column: 12, scope: !175)
+!177 = !DILocation(line: 63, column: 7, scope: !169)
+!178 = !DILocation(line: 64, column: 5, scope: !175)
+!179 = !DILocalVariable(name: "res", scope: !169, file: !1, line: 65, type: !4)
+!180 = !DILocation(line: 65, column: 17, scope: !169)
+!181 = !DILocation(line: 65, column: 39, scope: !169)
+!182 = !DILocation(line: 66, column: 15, scope: !169)
+!183 = !DILocation(line: 66, column: 3, scope: !169)
+!184 = !DILocation(line: 66, column: 8, scope: !169)
+!185 = !DILocation(line: 66, column: 13, scope: !169)
+!186 = !DILocation(line: 67, column: 29, scope: !169)
+!187 = !DILocation(line: 67, column: 34, scope: !169)
+!188 = !DILocation(line: 67, column: 22, scope: !169)
+!189 = !DILocation(line: 67, column: 3, scope: !169)
+!190 = !DILocation(line: 67, column: 8, scope: !169)
+!191 = !DILocation(line: 67, column: 13, scope: !169)
+!192 = !DILocalVariable(name: "i", scope: !193, file: !1, line: 69, type: !9)
+!193 = distinct !DILexicalBlock(scope: !169, file: !1, line: 69, column: 3)
+!194 = !DILocation(line: 69, column: 12, scope: !193)
+!195 = !DILocation(line: 69, column: 8, scope: !193)
+!196 = !DILocation(line: 69, column: 19, scope: !197)
+!197 = distinct !DILexicalBlock(scope: !193, file: !1, line: 69, column: 3)
+!198 = !DILocation(line: 69, column: 23, scope: !197)
+!199 = !DILocation(line: 69, column: 21, scope: !197)
+!200 = !DILocation(line: 69, column: 3, scope: !193)
+!201 = !DILocation(line: 70, column: 20, scope: !202)
+!202 = distinct !DILexicalBlock(scope: !197, file: !1, line: 69, column: 34)
+!203 = !DILocation(line: 70, column: 5, scope: !202)
+!204 = !DILocation(line: 70, column: 10, scope: !202)
+!205 = !DILocation(line: 70, column: 15, scope: !202)
+!206 = !DILocation(line: 70, column: 18, scope: !202)
+!207 = !DILocation(line: 71, column: 3, scope: !202)
+!208 = !DILocation(line: 69, column: 29, scope: !197)
+!209 = !DILocation(line: 69, column: 3, scope: !197)
+!210 = distinct !{!210, !200, !211, !166}
+!211 = !DILocation(line: 71, column: 3, scope: !193)
+!212 = !DILocation(line: 73, column: 10, scope: !169)
+!213 = !DILocation(line: 73, column: 3, scope: !169)
+!214 = !DILocation(line: 74, column: 1, scope: !169)
+!215 = distinct !DISubprogram(name: "caller", scope: !1, file: !1, line: 76, type: !216, scopeLine: 76, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !27)
+!216 = !DISubroutineType(types: !217)
+!217 = !{!9}
+!218 = !DILocalVariable(name: "size", scope: !215, file: !1, line: 77, type: !88)
+!219 = !DILocation(line: 77, column: 13, scope: !215)
+!220 = !DILocalVariable(name: "A", scope: !215, file: !1, line: 78, type: !4)
+!221 = !DILocation(line: 78, column: 17, scope: !215)
+!222 = !DILocation(line: 78, column: 21, scope: !215)
+!223 = !DILocalVariable(name: "B", scope: !215, file: !1, line: 79, type: !4)
+!224 = !DILocation(line: 79, column: 17, scope: !215)
+!225 = !DILocation(line: 79, column: 21, scope: !215)
+!226 = !DILocalVariable(name: "res", scope: !215, file: !1, line: 80, type: !11)
+!227 = !DILocation(line: 80, column: 18, scope: !215)
+!228 = !DILocation(line: 80, column: 41, scope: !215)
+!229 = !DILocalVariable(name: "ret", scope: !215, file: !1, line: 81, type: !9)
+!230 = !DILocation(line: 81, column: 7, scope: !215)
+!231 = !DILocalVariable(name: "err", scope: !215, file: !1, line: 83, type: !9)
+!232 = !DILocation(line: 83, column: 7, scope: !215)
+!233 = !DILocation(line: 83, column: 21, scope: !215)
+!234 = !DILocation(line: 83, column: 24, scope: !215)
+!235 = !DILocation(line: 83, column: 27, scope: !215)
+!236 = !DILocation(line: 83, column: 13, scope: !215)
+!237 = !DILocation(line: 84, column: 7, scope: !238)
+!238 = distinct !DILexicalBlock(scope: !215, file: !1, line: 84, column: 7)
+!239 = !DILocation(line: 84, column: 11, scope: !238)
+!240 = !DILocation(line: 84, column: 7, scope: !215)
+!241 = !DILocation(line: 85, column: 5, scope: !242)
+!242 = distinct !DILexicalBlock(scope: !238, file: !1, line: 84, column: 18)
+!243 = !DILocation(line: 88, column: 9, scope: !215)
+!244 = !DILocation(line: 88, column: 14, scope: !215)
+!245 = !DILocation(line: 88, column: 7, scope: !215)
+!246 = !DILocation(line: 89, column: 7, scope: !247)
+!247 = distinct !DILexicalBlock(scope: !215, file: !1, line: 89, column: 7)
+!248 = !DILocation(line: 89, column: 11, scope: !247)
+!249 = !DILocation(line: 89, column: 7, scope: !215)
+!250 = !DILocation(line: 90, column: 12, scope: !247)
+!251 = !DILocation(line: 90, column: 5, scope: !247)
+!252 = !DILocation(line: 92, column: 18, scope: !215)
+!253 = !DILocation(line: 92, column: 23, scope: !215)
+!254 = !DILocation(line: 92, column: 3, scope: !215)
+!255 = !DILabel(scope: !215, name: "cleanup", file: !1, line: 94)
+!256 = !DILocation(line: 94, column: 1, scope: !215)
+!257 = !DILocation(line: 95, column: 17, scope: !215)
+!258 = !DILocation(line: 95, column: 3, scope: !215)
+!259 = !DILocation(line: 96, column: 17, scope: !215)
+!260 = !DILocation(line: 96, column: 3, scope: !215)
+!261 = !DILocation(line: 97, column: 18, scope: !215)
+!262 = !DILocation(line: 97, column: 3, scope: !215)
+!263 = !DILocation(line: 99, column: 10, scope: !215)
+!264 = !DILocation(line: 99, column: 3, scope: !215)
+!265 = !DILocation(line: 100, column: 1, scope: !215)
Index: llvm/test/CodeGen/X86/stack-frame-printer.ll
===================================================================
--- /dev/null
+++ llvm/test/CodeGen/X86/stack-frame-printer.ll
@@ -0,0 +1,107 @@
+; Test basic output of the -print-stack-frame pass
+
+; RUN: llc -mcpu=corei7 -O1 -print-stack-frame < %s 2>&1 >/dev/null | FileCheck %s
+; RUN: llc -mcpu=corei7 -O0 -print-stack-frame < %s 2>&1 >/dev/null | FileCheck %s --check-prefix=NO_COLORING
+
+
+; CHECK: Offset{{.*}}Align{{.*}}Size
+; CHECK: [SP-88]{{.*}}16{{.*}}80
+; CHECK: buffer @ frame-diags.c:30
+; NO_COLORING: [SP-168]{{.*}}16{{.*}}80
+; CHECK: buffer2 @ frame-diags.c:33
+
+; ModuleID = 'frame-diags.c'
+source_filename = "frame-diags.c"
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; Function Attrs: nounwind uwtable
+define dso_local void @stackSizeWarning() local_unnamed_addr #0 !dbg !9 {
+entry:
+ %buffer = alloca [80 x i8], align 16
+ %buffer2 = alloca [80 x i8], align 16
+ call void @llvm.lifetime.start.p0(i64 80, ptr nonnull %buffer) #5, !dbg !24
+ call void @llvm.dbg.declare(metadata ptr %buffer, metadata !13, metadata !DIExpression()), !dbg !25
+ call void @doIt(ptr noundef nonnull %buffer) #5, !dbg !26
+ call void @llvm.lifetime.end.p0(i64 80, ptr nonnull %buffer) #5, !dbg !27
+ call void @llvm.lifetime.start.p0(i64 80, ptr nonnull %buffer2) #5, !dbg !28
+ call void @llvm.dbg.declare(metadata ptr %buffer2, metadata !19, metadata !DIExpression()), !dbg !29
+ call void @llvm.dbg.value(metadata i32 0, metadata !20, metadata !DIExpression()), !dbg !30
+ call void @llvm.dbg.value(metadata i64 1, metadata !22, metadata !DIExpression()), !dbg !30
+ call void @doIt(ptr noundef nonnull %buffer2) #5, !dbg !31
+ %call = call i32 @getNum(i64 noundef 0) #5, !dbg !32
+ %call2 = call i32 @getNum(i64 noundef 1) #5, !dbg !33
+ call void @llvm.lifetime.end.p0(i64 80, ptr nonnull %buffer2) #5, !dbg !34
+ ret void, !dbg !34
+}
+
+; Function Attrs: argmemonly mustprogress nocallback nofree nosync nounwind willreturn
+declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) #1
+
+; Function Attrs: mustprogress nocallback nofree nosync nounwind readnone speculatable willreturn
+declare void @llvm.dbg.declare(metadata, metadata, metadata) #2
+
+declare !dbg !35 void @doIt(ptr noundef) local_unnamed_addr #3
+
+; Function Attrs: argmemonly mustprogress nocallback nofree nosync nounwind willreturn
+declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) #1
+
+declare !dbg !40 i32 @getNum(i64 noundef) local_unnamed_addr #3
+
+; Function Attrs: nocallback nofree nosync nounwind readnone speculatable willreturn
+declare void @llvm.dbg.value(metadata, metadata, metadata) #4
+
+attributes #0 = { nounwind uwtable "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+attributes #1 = { argmemonly mustprogress nocallback nofree nosync nounwind willreturn }
+attributes #2 = { mustprogress nocallback nofree nosync nounwind readnone speculatable willreturn }
+attributes #3 = { "frame-pointer"="none" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+attributes #4 = { nocallback nofree nosync nounwind readnone speculatable willreturn }
+attributes #5 = { nounwind }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!2, !3, !4, !5, !6, !7}
+!llvm.ident = !{!8}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "Fuchsia clang version 16.0.0 ([email protected]:llvm/llvm-project.git bb51a99e67747be81c9b523fd5ddcc8bf91a1ffb)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
+!1 = !DIFile(filename: "frame-diags.c", directory: "/usr/local/google/home/paulkirth/llvm-sysroot/clang/test/Frontend", checksumkind: CSK_MD5, checksum: "01b5d69ce5387b02de2d1191b28a0b7f")
+!2 = !{i32 7, !"Dwarf Version", i32 5}
+!3 = !{i32 2, !"Debug Info Version", i32 3}
+!4 = !{i32 1, !"wchar_size", i32 4}
+!5 = !{i32 8, !"PIC Level", i32 2}
+!6 = !{i32 7, !"PIE Level", i32 2}
+!7 = !{i32 7, !"uwtable", i32 2}
+!8 = !{!"Fuchsia clang version 16.0.0 ([email protected]:llvm/llvm-project.git bb51a99e67747be81c9b523fd5ddcc8bf91a1ffb)"}
+!9 = distinct !DISubprogram(name: "stackSizeWarning", scope: !1, file: !1, line: 28, type: !10, scopeLine: 28, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !12)
+!10 = !DISubroutineType(types: !11)
+!11 = !{null}
+!12 = !{!13, !19, !20, !22}
+!13 = !DILocalVariable(name: "buffer", scope: !14, file: !1, line: 30, type: !15)
+!14 = distinct !DILexicalBlock(scope: !9, file: !1, line: 29, column: 3)
+!15 = !DICompositeType(tag: DW_TAG_array_type, baseType: !16, size: 640, elements: !17)
+!16 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
+!17 = !{!18}
+!18 = !DISubrange(count: 80)
+!19 = !DILocalVariable(name: "buffer2", scope: !9, file: !1, line: 33, type: !15)
+!20 = !DILocalVariable(name: "a", scope: !9, file: !1, line: 34, type: !21)
+!21 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!22 = !DILocalVariable(name: "b", scope: !9, file: !1, line: 35, type: !23)
+!23 = !DIBasicType(name: "long", size: 64, encoding: DW_ATE_signed)
+!24 = !DILocation(line: 30, column: 5, scope: !14)
+!25 = !DILocation(line: 30, column: 10, scope: !14)
+!26 = !DILocation(line: 31, column: 5, scope: !14)
+!27 = !DILocation(line: 32, column: 3, scope: !9)
+!28 = !DILocation(line: 33, column: 3, scope: !9)
+!29 = !DILocation(line: 33, column: 8, scope: !9)
+!30 = !DILocation(line: 0, scope: !9)
+!31 = !DILocation(line: 36, column: 3, scope: !9)
+!32 = !DILocation(line: 38, column: 3, scope: !9)
+!33 = !DILocation(line: 39, column: 3, scope: !9)
+!34 = !DILocation(line: 40, column: 1, scope: !9)
+!35 = !DISubprogram(name: "doIt", scope: !1, file: !1, line: 21, type: !36, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !39)
+!36 = !DISubroutineType(types: !37)
+!37 = !{null, !38}
+!38 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !16, size: 64)
+!39 = !{}
+!40 = !DISubprogram(name: "getNum", scope: !1, file: !1, line: 23, type: !41, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !39)
+!41 = !DISubroutineType(types: !42)
+!42 = !{!21, !23}
Index: llvm/lib/CodeGen/TargetPassConfig.cpp
===================================================================
--- llvm/lib/CodeGen/TargetPassConfig.cpp
+++ llvm/lib/CodeGen/TargetPassConfig.cpp
@@ -159,6 +159,10 @@
PrintAfterISel("print-after-isel", cl::init(false), cl::Hidden,
cl::desc("Print machine instrs after ISel"));
+static cl::opt<bool>
+ PrintStackFrame("print-stack-frame", cl::init(false), cl::Hidden,
+ cl::desc("Print Stack Frame"));
+
static cl::opt<GlobalISelAbortMode> EnableGlobalISelAbort(
"global-isel-abort", cl::Hidden,
cl::desc("Enable abort calls when \"global\" instruction selection "
@@ -1297,6 +1301,9 @@
if (!DisableCFIFixup && TM->Options.EnableCFIFixup)
addPass(createCFIFixup());
+ if(PrintStackFrame)
+ PM->add(createStackFramePrinterPass(dbgs(), "Stack Layout"));
+
// Add passes that directly emit MI after all other MI passes.
addPreEmitPass2();
Index: llvm/lib/CodeGen/StackFramePrinterPass.cpp
===================================================================
--- /dev/null
+++ llvm/lib/CodeGen/StackFramePrinterPass.cpp
@@ -0,0 +1,254 @@
+//===-- MachineFunctionPrinterPass.cpp ------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// StackFramePrinterPass implementation. Prints a textual representation of
+// the stack frame. When possible it prints the values that occupy a stack slot
+// using any available debug information.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/CodeGen/MachineFrameInfo.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/Passes.h"
+#include "llvm/CodeGen/SlotIndexes.h"
+#include "llvm/CodeGen/TargetFrameLowering.h"
+#include "llvm/CodeGen/TargetSubtargetInfo.h"
+#include "llvm/IR/DebugInfoMetadata.h"
+#include "llvm/IR/PrintPasses.h"
+#include "llvm/InitializePasses.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <iomanip>
+#include <sstream>
+
+using namespace llvm;
+
+namespace {
+
+constexpr int OffsetWidth = 4 + 7;
+constexpr int SpillWidth = 5;
+constexpr int AlignWidth = 9;
+constexpr int SizeWidth = 10;
+
+constexpr size_t MaxLine =
+ std::min(75, OffsetWidth + SpillWidth + AlignWidth + SizeWidth + 3);
+
+/// StackFramePrinterPass - This is a pass to dump the stack frame of a
+/// MachineFunction.
+///
+struct StackFramePrinterPass : public MachineFunctionPass {
+ using SlotDbgMap =
+ SmallDenseMap<int, SmallPtrSet<const DILocalVariable *, 4>>;
+ static char ID;
+
+ raw_ostream &OS;
+ const std::string Banner;
+
+ struct SlotData {
+ int Slot;
+ int Size;
+ int Align;
+ int Offset;
+ bool IsSpillSlot;
+ bool Fixed;
+ };
+
+ StackFramePrinterPass() : MachineFunctionPass(ID), OS(dbgs()) {}
+ StackFramePrinterPass(raw_ostream &OS, const std::string &Banner)
+ : MachineFunctionPass(ID), OS(OS), Banner(Banner) {}
+
+ StringRef getPassName() const override { return "StackFrame Printer"; }
+
+ void getAnalysisUsage(AnalysisUsage &AU) const override {
+ AU.setPreservesAll();
+ MachineFunctionPass::getAnalysisUsage(AU);
+ }
+
+ bool runOnMachineFunction(MachineFunction &MF) override {
+ if (!isFunctionInPrintList(MF.getName()))
+ return false;
+
+ OS << "# " << Banner << ": " << MF.getName() << "\n";
+
+ auto SlotMap = genSlotDbgMapping(MF);
+ printFrame(MF, OS, SlotMap);
+
+ return false;
+ }
+
+ std::string genFieldInt(int Width, int I) const {
+ std::stringstream SS;
+ SS.setf(std::ios_base::left);
+ SS << std::setw(Width) << I;
+ return SS.str();
+ }
+
+ std::string genFieldString(int Width, std::string S) const {
+ std::stringstream SS;
+ SS.setf(std::ios_base::left);
+ SS << std::setw(Width) << S;
+ return SS.str();
+ }
+
+ std::string genFieldOffset(int I) const {
+ std::stringstream SS;
+ SS.setf(std::ios_base::left);
+ SS << "[SP";
+ const auto *Op = (I < 0) ? "" : "+";
+ SS << Op << I << "]";
+ return SS.str();
+ }
+
+ std::string genBody(int Idx, SlotData &D) const {
+ std::stringstream SS;
+ SS.setf(std::ios_base::left);
+
+ SS << std::setw(OffsetWidth) << genFieldOffset(D.Offset) << " ";
+ SS << genFieldString(SpillWidth, D.IsSpillSlot ? "Spill" : "") << " ";
+ SS << genFieldInt(AlignWidth, D.Align) << " ";
+ SS << genFieldInt(SizeWidth, D.Size);
+ return SS.str();
+ };
+
+ std::string genHeader() const {
+ std::stringstream SS;
+ SS.setf(std::ios_base::left);
+ SS << genFieldString(OffsetWidth, "Offset") << " ";
+ SS << genFieldString(SpillWidth, "") << " ";
+ SS << genFieldString(AlignWidth, "Align") << " ";
+ SS << genFieldString(SizeWidth, "Size");
+ return SS.str();
+ };
+
+ void printSourceLoc(raw_ostream &OS, const llvm::DILocalVariable *N) const {
+ OS << " " << N->getName().str() << " @ " << N->getFilename() << ":"
+ << N->getLine();
+ OS << "\n";
+ }
+
+ void printRow(raw_ostream &OS, std::string S) const {
+ std::stringstream SS;
+ SS.setf(std::ios_base::left);
+ SS << std::setw(MaxLine) << S;
+ OS << " " << SS.str() << " \n";
+ };
+
+ void printFrame(const MachineFunction &MF, raw_ostream &OS,
+ SlotDbgMap &SlotMap) const {
+ auto &MFI = MF.getFrameInfo();
+
+ if (!MFI.hasStackObjects())
+ return;
+
+ const TargetFrameLowering *FI = MF.getSubtarget().getFrameLowering();
+ int ValOffset = (FI ? FI->getOffsetOfLocalArea() : 0);
+
+ std::vector<SlotData> SlotInfo;
+ SmallDenseMap<int, int> SlotOffsetMap;
+ auto NumObj = MFI.getNumObjects();
+ auto ObjBeg = MFI.getObjectIndexBegin();
+ auto ObjEnd = MFI.getObjectIndexEnd();
+ int NumFixed = MFI.getNumFixedObjects();
+
+ SlotInfo.reserve(NumObj);
+ SlotOffsetMap.reserve(NumObj);
+ // initialize slot info
+ for (auto Idx = ObjBeg, EndIdx = ObjEnd; Idx != EndIdx; ++Idx) {
+ SlotData D;
+ uint64_t Size = MFI.getObjectSize(Idx);
+
+ // This is a dead slot, so skip it
+ if (Size == ~0ULL) {
+ continue;
+ }
+
+ D.Slot = (int)(Idx);
+ // If Size == 0, then its a variable size object...
+ D.Size = Size;
+ D.Align = MFI.getObjectAlign(Idx).value();
+ D.Fixed = (Idx < NumFixed);
+ D.IsSpillSlot = MFI.isSpillSlotObjectIndex(Idx);
+ D.Offset = MFI.getObjectOffset(Idx) - ValOffset;
+ SlotInfo.push_back(D);
+ SlotOffsetMap[D.Slot] = D.Offset;
+ }
+
+ // sort the ordering, to match the actual layout in memory
+ std::sort(SlotInfo.begin(), SlotInfo.end(),
+ [](SlotData &A, SlotData &B) { return A.Offset > B.Offset; });
+
+ printRow(OS, genHeader());
+
+ int Idx = 0;
+ for (auto L : SlotInfo) {
+ std::stringstream SS;
+ auto Body = genBody(Idx++, L);
+ printRow(OS, Body);
+ for (auto *N : SlotMap[L.Slot])
+ printSourceLoc(OS, N);
+ }
+ OS << "\n";
+ }
+
+ // We need to generate a mapping of slots to the values that are stored to
+ // them This infomation is lost by the time we need to print out the frame, so
+ // we reconstruct it here by walking the CFG, and generating the mapping.
+ SlotDbgMap genSlotDbgMapping(MachineFunction &MF) {
+ SlotDbgMap SlotDebugMap;
+ SmallVector<MachineInstr *> Dbg;
+
+ // add variables to the map
+ for (auto &DI : MF.getVariableDbgInfo()) {
+ SlotDebugMap[DI.Slot].insert(DI.Var);
+ }
+
+ // Then add all the spills that have debug data
+ for (auto &MBB : MF) {
+ for (auto &MI : MBB) {
+ if (MI.getNumMemOperands() == 0)
+ continue;
+ for (MachineMemOperand *MO : MI.memoperands()) {
+ if (!MO->isStore())
+ continue;
+ auto *FI = dyn_cast_or_null<FixedStackPseudoSourceValue>(
+ MO->getPseudoValue());
+ if (!FI)
+ continue;
+ auto FrameIdx = FI->getFrameIndex();
+ Dbg.clear();
+ MI.collectDebugValues(Dbg);
+
+ for (auto *MI : Dbg)
+ SlotDebugMap[FrameIdx].insert(MI->getDebugVariable());
+ }
+ }
+ }
+
+ return SlotDebugMap;
+ }
+};
+
+char StackFramePrinterPass::ID = 0;
+} // namespace
+
+char &llvm::StackFramePrinterPassID = StackFramePrinterPass::ID;
+INITIALIZE_PASS(StackFramePrinterPass, "stackframe-printer",
+ "Stack Frame Printer", false, false)
+
+namespace llvm {
+/// Returns a newly-created MachineFunction Printer pass. The
+/// default banner is empty.
+///
+MachineFunctionPass *createStackFramePrinterPass(raw_ostream &OS,
+ const std::string &Banner) {
+ return new StackFramePrinterPass(OS, Banner);
+}
+
+} // namespace llvm
Index: llvm/lib/CodeGen/PrologEpilogInserter.cpp
===================================================================
--- llvm/lib/CodeGen/PrologEpilogInserter.cpp
+++ llvm/lib/CodeGen/PrologEpilogInserter.cpp
@@ -51,6 +51,7 @@
#include "llvm/IR/Function.h"
#include "llvm/IR/InlineAsm.h"
#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/ModuleSlotTracker.h"
#include "llvm/InitializePasses.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/Pass.h"
@@ -289,6 +290,9 @@
if (StackSize > Threshold) {
DiagnosticInfoStackSize DiagStackSize(F, StackSize, Threshold, DS_Warning);
F.getContext().diagnose(DiagStackSize);
+ //TODO: print stats here about stack usage:
+ // How much total memory
+ // What % are locals vs spills
}
ORE->emit([&]() {
return MachineOptimizationRemarkAnalysis(DEBUG_TYPE, "StackSize",
Index: llvm/lib/CodeGen/MachineFrameInfo.cpp
===================================================================
--- llvm/lib/CodeGen/MachineFrameInfo.cpp
+++ llvm/lib/CodeGen/MachineFrameInfo.cpp
@@ -20,9 +20,12 @@
#include "llvm/CodeGen/TargetRegisterInfo.h"
#include "llvm/CodeGen/TargetSubtargetInfo.h"
#include "llvm/Config/llvm-config.h"
+#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include <cassert>
+#include <iomanip>
+#include <sstream>
#define DEBUG_TYPE "codegen"
Index: llvm/lib/CodeGen/CodeGen.cpp
===================================================================
--- llvm/lib/CodeGen/CodeGen.cpp
+++ llvm/lib/CodeGen/CodeGen.cpp
@@ -115,6 +115,7 @@
initializeSjLjEHPreparePass(Registry);
initializeSlotIndexesPass(Registry);
initializeStackColoringPass(Registry);
+ initializeStackFramePrinterPassPass(Registry);
initializeStackMapLivenessPass(Registry);
initializeStackProtectorPass(Registry);
initializeStackSlotColoringPass(Registry);
Index: llvm/lib/CodeGen/CMakeLists.txt
===================================================================
--- llvm/lib/CodeGen/CMakeLists.txt
+++ llvm/lib/CodeGen/CMakeLists.txt
@@ -207,6 +207,7 @@
SpillPlacement.cpp
SplitKit.cpp
StackColoring.cpp
+ StackFramePrinterPass.cpp
StackMapLivenessAnalysis.cpp
StackMaps.cpp
StackProtector.cpp
Index: llvm/include/llvm/InitializePasses.h
===================================================================
--- llvm/include/llvm/InitializePasses.h
+++ llvm/include/llvm/InitializePasses.h
@@ -402,6 +402,7 @@
void initializeSpeculativeExecutionLegacyPassPass(PassRegistry&);
void initializeSpillPlacementPass(PassRegistry&);
void initializeStackColoringPass(PassRegistry&);
+void initializeStackFramePrinterPassPass(PassRegistry&);
void initializeStackMapLivenessPass(PassRegistry&);
void initializeStackProtectorPass(PassRegistry&);
void initializeStackSafetyGlobalInfoWrapperPassPass(PassRegistry &);
Index: llvm/include/llvm/CodeGen/Passes.h
===================================================================
--- llvm/include/llvm/CodeGen/Passes.h
+++ llvm/include/llvm/CodeGen/Passes.h
@@ -63,6 +63,12 @@
createMachineFunctionPrinterPass(raw_ostream &OS,
const std::string &Banner ="");
+ /// StackFramePrinter pass - This pass prints out the machine function's
+ /// stack frame to the given stream as a debugging tool.
+ MachineFunctionPass *
+ createStackFramePrinterPass(raw_ostream &OS,
+ const std::string &Banner ="");
+
/// MIRPrinting pass - this pass prints out the LLVM IR into the given stream
/// using the MIR serialization format.
MachineFunctionPass *createPrintMIRPass(raw_ostream &OS);
@@ -260,6 +266,10 @@
/// It merges disjoint allocas to reduce the stack size.
extern char &StackColoringID;
+ /// StackFramePrinter - This pass prints the stack frame layout and variable
+ /// mappings.
+ extern char &StackFramePrinterPassID;
+
/// IfConverter - This pass performs machine code if conversion.
extern char &IfConverterID;
Index: llvm/include/llvm/CodeGen/MachineFrameInfo.h
===================================================================
--- llvm/include/llvm/CodeGen/MachineFrameInfo.h
+++ llvm/include/llvm/CodeGen/MachineFrameInfo.h
@@ -14,6 +14,7 @@
#define LLVM_CODEGEN_MACHINEFRAMEINFO_H
#include "llvm/ADT/SmallVector.h"
+#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/Register.h"
#include "llvm/Support/Alignment.h"
#include <cassert>
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits