Skip to content

Instantly share code, notes, and snippets.

@OCHyams
Last active October 22, 2020 17:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save OCHyams/29ec463e82b70955c9fc5542f0b69cd7 to your computer and use it in GitHub Desktop.
Save OCHyams/29ec463e82b70955c9fc5542f0b69cd7 to your computer and use it in GitHub Desktop.
Here's a walkthrough of the example from https://llvm.org/47946 with IR.
$ cat -n test.c
1 int g;
2 __attribute__((__always_inline__))
3 static void use(int* p) {
4 g = *p;
5 *p = 0xff;
6 }
7 __attribute__((__noinline__))
8 void fun(int param) {
9 use(&param);
10 }
11 int main() {
12 fun(5);
13 }
$ clang test.c -O2 -g -print-after-all -filter-print-funcs=fun
# IR for 'fun' before optimisations run.
*** IR Dump After Module Verifier ***
; Function Attrs: noinline nounwind uwtable
define dso_local void @fun(i32 %param) #0 !dbg !11 {
entry:
%param.addr = alloca i32, align 4
store i32 %param, i32* %param.addr, align 4, !tbaa !16
call void @llvm.dbg.declare(metadata i32* %param.addr, metadata !15, metadata !DIExpression()), !dbg !20
call void @use(i32* %param.addr), !dbg !21
ret void, !dbg !22
}
!15 = !DILocalVariable(name: "param", arg: 1, scope: !11, file: !3, line: 8, type: !6)
--- snip ---
# InstCombine runs LowerDbgDeclare, converting the dbg.declare to a series of
# dbg.values.
*** IR Dump After Combine redundant instructions ***
; Function Attrs: noinline nounwind uwtable
define dso_local void @fun(i32 %param) local_unnamed_addr #0 !dbg !11 {
entry:
%param.addr = alloca i32, align 4
call void @llvm.dbg.value(metadata i32 %param, metadata !15, metadata !DIExpression()), !dbg !16
store i32 %param, i32* %param.addr, align 4, !tbaa !17
call void @llvm.dbg.value(metadata i32* %param.addr, metadata !15, metadata !DIExpression(DW_OP_deref)), !dbg !16
call fastcc void @use(i32* nonnull %param.addr), !dbg !21
ret void, !dbg !22
}
!15 = !DILocalVariable(name: "param", arg: 1, scope: !11, file: !3, line: 8, type: !6)
--- snip ---
# 'use' is inlined into 'fun'. Notice how there is now a store to %param.addr
# which doesn't have an assoicated dbg.value. This doesn't matter at the moment
# because we still have the dbg.value+deref that was inserted before the (now
# inlined) call site.
*** IR Dump After Function Integration/Inlining ***; Function Attrs: noinline nounwind uwtable
define dso_local void @fun(i32 %param) local_unnamed_addr #0 !dbg !11 {
entry:
%param.addr = alloca i32, align 4
call void @llvm.dbg.value(metadata i32 %param, metadata !15, metadata !DIExpression()), !dbg !16
store i32 %param, i32* %param.addr, align 4, !tbaa !17
call void @llvm.dbg.value(metadata i32* %param.addr, metadata !15, metadata !DIExpression(DW_OP_deref)), !dbg !16
call void @llvm.dbg.value(metadata i32* %param.addr, metadata !21, metadata !DIExpression()), !dbg !27
%0 = load i32, i32* %param.addr, align 4, !dbg !29, !tbaa !17
store i32 %0, i32* @g, align 4, !dbg !30, !tbaa !17
store i32 255, i32* %param.addr, align 4, !dbg !31, !tbaa !17
ret void, !dbg !32
}
!15 = !DILocalVariable(name: "param", arg: 1, scope: !11, file: !3, line: 8, type: !6)
!21 = !DILocalVariable(name: "p", arg: 1, scope: !23, file: !3, line: 3, type: !26)
--- snip ---
# SROA runs mem2reg, which removes the redundant 0xff store and the remaining
# store/load pair for %param.addr. The alloca is then removed, and as of D89810,
# the dbg.value+deref is too. This will cause us to provide the misleading
# location %param for 'param' after the store to 'g', when we would ideally
# provide a constant value 0xff.
*** IR Dump After SROA ***
; Function Attrs: nofree noinline norecurse nounwind uwtable writeonly
define dso_local void @fun(i32 %param) local_unnamed_addr #0 !dbg !11 {
entry:
call void @llvm.dbg.value(metadata i32 %param, metadata !15, metadata !DIExpression()), !dbg !16
call void @llvm.dbg.value(metadata i32* undef, metadata !17, metadata !DIExpression()), !dbg !23
store i32 %param, i32* @g, align 4, !dbg !25, !tbaa !26
ret void, !dbg !30
}
!15 = !DILocalVariable(name: "param", arg: 1, scope: !11, file: !3, line: 8, type: !6)
!17 = !DILocalVariable(name: "p", arg: 1, scope: !23, file: !3, line: 3, type: !26)
-- snip --
The proposed solution would make the following change to the IR after inlining:
store i32 %0, i32* @g, align 4, !dbg !30, !tbaa !17
store i32 255, i32* %param.addr, align 4, !dbg !31, !tbaa !17
[+call void @llvm.dbg.value(metadata i32 255, metadata !15, metadata !DIExpression()), !dbg !16+]
ret void, !dbg !32
And after SROA we're left with:
define dso_local void @fun(i32 %param) local_unnamed_addr #0 !dbg !11 {
entry:
call void @llvm.dbg.value(metadata i32 %param, metadata !15, metadata !DIExpression()), !dbg !16
call void @llvm.dbg.value(metadata i32* undef, metadata !17, metadata !DIExpression()), !dbg !23
store i32 %param, i32* @g, align 4, !dbg !25, !tbaa !26
[+call void @llvm.dbg.value(metadata i32 255, metadata !15, metadata !DIExpression()), !dbg !16+]
ret void, !dbg !30
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment