1;; Test callsite context graph generation for call graph with with MIBs 2;; that have pruned contexts that partially match multiple inlined 3;; callsite contexts, requiring duplication of context ids and nodes 4;; while matching callsite nodes onto the graph. 5;; 6;; Original code looks like: 7;; 8;; char *D() { 9;; return new char[10]; 10;; } 11;; 12;; char *F() { 13;; return D(); 14;; } 15;; 16;; char *C() { 17;; return D(); 18;; } 19;; 20;; char *B() { 21;; return C(); 22;; } 23;; 24;; char *E() { 25;; return C(); 26;; } 27;; int main(int argc, char **argv) { 28;; char *x = B(); // cold 29;; char *y = E(); // cold 30;; char *z = F(); // default 31;; memset(x, 0, 10); 32;; memset(y, 0, 10); 33;; memset(z, 0, 10); 34;; delete[] z; 35;; sleep(10); 36;; delete[] x; 37;; delete[] y; 38;; return 0; 39;; } 40;; 41;; Code compiled with -mllvm -memprof-ave-lifetime-cold-threshold=5 so that the 42;; memory freed after sleep(10) results in cold lifetimes. 43;; 44;; The code below was created by forcing inlining of C into both B and E. 45;; Since both allocation contexts via C are cold, the matched memprof 46;; metadata has the context pruned above C's callsite. This requires 47;; matching the stack node for C to callsites where it was inlined (i.e. 48;; the callsites in B and E that have callsite metadata that includes C's). 49;; It also requires duplication of that node in the graph as well as the 50;; duplication of the context ids along that path through the graph, 51;; so that we can represent the duplicated (via inlining) C callsite. 52;; 53;; The IR was then reduced using llvm-reduce with the expected FileCheck input. 54 55;; -stats requires asserts 56; REQUIRES: asserts 57 58; RUN: opt -passes=memprof-context-disambiguation \ 59; RUN: -memprof-verify-ccg -memprof-verify-nodes -memprof-dump-ccg \ 60; RUN: -memprof-export-to-dot -memprof-dot-file-path-prefix=%t. \ 61; RUN: %s -S 2>&1 | FileCheck %s --check-prefix=DUMP 62 63; RUN: cat %t.ccg.prestackupdate.dot | FileCheck %s --check-prefix=DOTPRE 64; RUN: cat %t.ccg.postbuild.dot | FileCheck %s --check-prefix=DOTPOST 65;; We should clone D once for the cold allocations via C. 66; RUN: cat %t.ccg.cloned.dot | FileCheck %s --check-prefix=DOTCLONED 67 68target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" 69target triple = "x86_64-unknown-linux-gnu" 70 71define internal ptr @_Z1Dv() { 72entry: 73 %call = call noalias noundef nonnull ptr @_Znam(i64 noundef 10) #6, !memprof !0, !callsite !5 74 ret ptr null 75} 76 77declare ptr @_Znam(i64) 78 79define internal ptr @_Z1Fv() #0 { 80entry: 81 %call = call noundef ptr @_Z1Dv(), !callsite !6 82 ret ptr null 83} 84 85; Function Attrs: mustprogress noinline optnone uwtable 86define internal ptr @_Z1Cv() #1 { 87entry: 88 %call = call noundef ptr @_Z1Dv(), !callsite !7 89 ret ptr null 90} 91 92; Function Attrs: mustprogress noinline optnone uwtable 93define internal ptr @_Z1Bv() #1 { 94entry: 95 %call.i = call noundef ptr @_Z1Dv(), !callsite !8 96 ret ptr null 97} 98 99; Function Attrs: mustprogress noinline optnone uwtable 100define internal ptr @_Z1Ev() #1 { 101entry: 102 %call.i = call noundef ptr @_Z1Dv(), !callsite !9 103 ret ptr null 104} 105 106; Function Attrs: noinline 107declare i32 @main() #2 108 109; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: write) 110declare void @llvm.memset.p0.i64(ptr nocapture writeonly, i8, i64, i1 immarg) #3 111 112; Function Attrs: nounwind 113declare void @_ZdaPv() #4 114 115declare i32 @sleep() #5 116 117attributes #0 = { "disable-tail-calls"="true" } 118attributes #1 = { mustprogress noinline optnone uwtable "disable-tail-calls"="true" "frame-pointer"="all" "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" } 119attributes #2 = { noinline } 120attributes #3 = { nocallback nofree nounwind willreturn memory(argmem: write) } 121attributes #4 = { nounwind } 122attributes #5 = { "no-trapping-math"="true" } 123attributes #6 = { builtin } 124 125!0 = !{!1, !3} 126!1 = !{!2, !"cold"} 127!2 = !{i64 6541423618768552252, i64 -6270142974039008131} 128!3 = !{!4, !"notcold"} 129!4 = !{i64 6541423618768552252, i64 -4903163940066524832} 130!5 = !{i64 6541423618768552252} 131!6 = !{i64 -4903163940066524832} 132!7 = !{i64 -6270142974039008131} 133!8 = !{i64 -6270142974039008131, i64 -184525619819294889} 134!9 = !{i64 -6270142974039008131, i64 1905834578520680781} 135 136 137;; After adding only the alloc node memprof metadata, we only have 2 contexts. 138 139; DUMP: CCG before updating call stack chains: 140; DUMP: Callsite Context Graph: 141; DUMP: Node [[D:0x[a-z0-9]+]] 142; DUMP: %call = call noalias noundef nonnull ptr @_Znam(i64 noundef 10) #6 (clone 0) 143; DUMP: AllocTypes: NotColdCold 144; DUMP: ContextIds: 1 2 145; DUMP: CalleeEdges: 146; DUMP: CallerEdges: 147; DUMP: Edge from Callee [[D]] to Caller: [[C:0x[a-z0-9]+]] AllocTypes: Cold ContextIds: 1 148; DUMP: Edge from Callee [[D]] to Caller: [[F:0x[a-z0-9]+]] AllocTypes: NotCold ContextIds: 2 149 150; DUMP: Node [[C]] 151; DUMP: null Call 152; DUMP: AllocTypes: Cold 153; DUMP: ContextIds: 1 154; DUMP: CalleeEdges: 155; DUMP: Edge from Callee [[D]] to Caller: [[C]] AllocTypes: Cold ContextIds: 1 156; DUMP: CallerEdges: 157 158; DUMP: Node [[F]] 159; DUMP: null Call 160; DUMP: AllocTypes: NotCold 161; DUMP: ContextIds: 2 162; DUMP: CalleeEdges: 163; DUMP: Edge from Callee [[D]] to Caller: [[F]] AllocTypes: NotCold ContextIds: 2 164; DUMP: CallerEdges: 165 166;; After updating for callsite metadata, we should have generated context ids 3 and 4, 167;; along with 2 new nodes for those callsites. All have the same allocation type 168;; behavior as the original C node. 169 170; DUMP: CCG before cloning: 171; DUMP: Callsite Context Graph: 172; DUMP: Node [[D]] 173; DUMP: %call = call noalias noundef nonnull ptr @_Znam(i64 noundef 10) #6 (clone 0) 174; DUMP: AllocTypes: NotColdCold 175; DUMP: ContextIds: 1 2 3 4 176; DUMP: CalleeEdges: 177; DUMP: CallerEdges: 178; DUMP: Edge from Callee [[D]] to Caller: [[F]] AllocTypes: NotCold ContextIds: 2 179; DUMP: Edge from Callee [[D]] to Caller: [[C2:0x[a-z0-9]+]] AllocTypes: Cold ContextIds: 3 180; DUMP: Edge from Callee [[D]] to Caller: [[B:0x[a-z0-9]+]] AllocTypes: Cold ContextIds: 4 181; DUMP: Edge from Callee [[D]] to Caller: [[E:0x[a-z0-9]+]] AllocTypes: Cold ContextIds: 1 182 183; DUMP: Node [[F]] 184; DUMP: %call = call noundef ptr @_Z1Dv() (clone 0) 185; DUMP: AllocTypes: NotCold 186; DUMP: ContextIds: 2 187; DUMP: CalleeEdges: 188; DUMP: Edge from Callee [[D]] to Caller: [[F]] AllocTypes: NotCold ContextIds: 2 189; DUMP: CallerEdges: 190 191; DUMP: Node [[C2]] 192; DUMP: %call = call noundef ptr @_Z1Dv() (clone 0) 193; DUMP: AllocTypes: Cold 194; DUMP: ContextIds: 3 195; DUMP: CalleeEdges: 196; DUMP: Edge from Callee [[D]] to Caller: [[C2]] AllocTypes: Cold ContextIds: 3 197; DUMP: CallerEdges: 198 199; DUMP: Node [[B]] 200; DUMP: %call.i = call noundef ptr @_Z1Dv() (clone 0) 201; DUMP: AllocTypes: Cold 202; DUMP: ContextIds: 4 203; DUMP: CalleeEdges: 204; DUMP: Edge from Callee [[D]] to Caller: [[B]] AllocTypes: Cold ContextIds: 4 205; DUMP: CallerEdges: 206 207; DUMP: Node [[E]] 208; DUMP: %call.i = call noundef ptr @_Z1Dv() (clone 0) 209; DUMP: AllocTypes: Cold 210; DUMP: ContextIds: 1 211; DUMP: CalleeEdges: 212; DUMP: Edge from Callee [[D]] to Caller: [[E]] AllocTypes: Cold ContextIds: 1 213; DUMP: CallerEdges: 214 215; DUMP: CCG after cloning: 216; DUMP: Callsite Context Graph: 217; DUMP: Node [[D]] 218; DUMP: %call = call noalias noundef nonnull ptr @_Znam(i64 noundef 10) #6 (clone 0) 219; DUMP: AllocTypes: NotCold 220; DUMP: ContextIds: 2 221; DUMP: CalleeEdges: 222; DUMP: CallerEdges: 223; DUMP: Edge from Callee [[D]] to Caller: [[F]] AllocTypes: NotCold ContextIds: 2 224; DUMP: Clones: [[D2:0x[a-z0-9]+]] 225 226; DUMP: Node [[F]] 227; DUMP: %call = call noundef ptr @_Z1Dv() (clone 0) 228; DUMP: AllocTypes: NotCold 229; DUMP: ContextIds: 2 230; DUMP: CalleeEdges: 231; DUMP: Edge from Callee [[D]] to Caller: [[F]] AllocTypes: NotCold ContextIds: 2 232; DUMP: CallerEdges: 233 234; DUMP: Node [[C2]] 235; DUMP: %call = call noundef ptr @_Z1Dv() (clone 0) 236; DUMP: AllocTypes: Cold 237; DUMP: ContextIds: 3 238; DUMP: CalleeEdges: 239; DUMP: Edge from Callee [[D2]] to Caller: [[C2]] AllocTypes: Cold ContextIds: 3 240; DUMP: CallerEdges: 241 242; DUMP: Node [[B]] 243; DUMP: %call.i = call noundef ptr @_Z1Dv() (clone 0) 244; DUMP: AllocTypes: Cold 245; DUMP: ContextIds: 4 246; DUMP: CalleeEdges: 247; DUMP: Edge from Callee [[D2]] to Caller: [[B]] AllocTypes: Cold ContextIds: 4 248; DUMP: CallerEdges: 249 250; DUMP: Node [[E]] 251; DUMP: %call.i = call noundef ptr @_Z1Dv() (clone 0) 252; DUMP: AllocTypes: Cold 253; DUMP: ContextIds: 1 254; DUMP: CalleeEdges: 255; DUMP: Edge from Callee [[D2]] to Caller: [[E]] AllocTypes: Cold ContextIds: 1 256; DUMP: CallerEdges: 257 258; DUMP: Node [[D2]] 259; DUMP: %call = call noalias noundef nonnull ptr @_Znam(i64 noundef 10) #6 (clone 0) 260; DUMP: AllocTypes: Cold 261; DUMP: ContextIds: 1 3 4 262; DUMP: CalleeEdges: 263; DUMP: CallerEdges: 264; DUMP: Edge from Callee [[D2]] to Caller: [[E:0x[a-z0-9]+]] AllocTypes: Cold ContextIds: 1 265; DUMP: Edge from Callee [[D2]] to Caller: [[C2:0x[a-z0-9]+]] AllocTypes: Cold ContextIds: 3 266; DUMP: Edge from Callee [[D2]] to Caller: [[B:0x[a-z0-9]+]] AllocTypes: Cold ContextIds: 4 267; DUMP: Clone of [[D]] 268 269 270; DOTPRE: digraph "prestackupdate" { 271; DOTPRE: label="prestackupdate"; 272; DOTPRE: Node[[D:0x[a-z0-9]+]] [shape=record,tooltip="N[[D]] ContextIds: 1 2",fillcolor="mediumorchid1",style="filled",style="filled",label="{OrigId: Alloc0\n_Z1Dv -\> _Znam}"]; 273; DOTPRE: Node[[C:0x[a-z0-9]+]] [shape=record,tooltip="N[[C]] ContextIds: 1",fillcolor="cyan",style="filled",style="filled",label="{OrigId: 12176601099670543485\nnull call (external)}"]; 274; DOTPRE: Node[[C]] -> Node[[D]][tooltip="ContextIds: 1",fillcolor="cyan"]; 275; DOTPRE: Node[[F:0x[a-z0-9]+]] [shape=record,tooltip="N[[F]] ContextIds: 2",fillcolor="brown1",style="filled",style="filled",label="{OrigId: 13543580133643026784\nnull call (external)}"]; 276; DOTPRE: Node[[F]] -> Node[[D]][tooltip="ContextIds: 2",fillcolor="brown1"]; 277; DOTPRE: } 278 279 280; DOTPOST:digraph "postbuild" { 281; DOTPOST: label="postbuild"; 282; DOTPOST: Node[[D:0x[a-z0-9]+]] [shape=record,tooltip="N[[D]] ContextIds: 1 2 3 4",fillcolor="mediumorchid1",style="filled",style="filled",label="{OrigId: Alloc0\n_Z1Dv -\> _Znam}"]; 283; DOTPOST: Node[[F:0x[a-z0-9]+]] [shape=record,tooltip="N[[F]] ContextIds: 2",fillcolor="brown1",style="filled",style="filled",label="{OrigId: 13543580133643026784\n_Z1Fv -\> _Z1Dv}"]; 284; DOTPOST: Node[[F]] -> Node[[D]][tooltip="ContextIds: 2",fillcolor="brown1"]; 285; DOTPOST: Node[[C:0x[a-z0-9]+]] [shape=record,tooltip="N[[C]] ContextIds: 3",fillcolor="cyan",style="filled",style="filled",label="{OrigId: 0\n_Z1Cv -\> _Z1Dv}"]; 286; DOTPOST: Node[[C]] -> Node[[D]][tooltip="ContextIds: 3",fillcolor="cyan"]; 287; DOTPOST: Node[[B:0x[a-z0-9]+]] [shape=record,tooltip="N[[B]] ContextIds: 4",fillcolor="cyan",style="filled",style="filled",label="{OrigId: 0\n_Z1Bv -\> _Z1Dv}"]; 288; DOTPOST: Node[[B]] -> Node[[D]][tooltip="ContextIds: 4",fillcolor="cyan"]; 289; DOTPOST: Node[[E:0x[a-z0-9]+]] [shape=record,tooltip="N[[E]] ContextIds: 1",fillcolor="cyan",style="filled",style="filled",label="{OrigId: 0\n_Z1Ev -\> _Z1Dv}"]; 290; DOTPOST: Node[[E]] -> Node[[D]][tooltip="ContextIds: 1",fillcolor="cyan"]; 291; DOTPOST:} 292 293 294; DOTCLONED: digraph "cloned" { 295; DOTCLONED: label="cloned"; 296; DOTCLONED: Node[[D:0x[a-z0-9]+]] [shape=record,tooltip="N[[D]] ContextIds: 2",fillcolor="brown1",style="filled",style="filled",label="{OrigId: Alloc0\n_Z1Dv -\> _Znam}"]; 297; DOTCLONED: Node[[F:0x[a-z0-9]+]] [shape=record,tooltip="N[[F]] ContextIds: 2",fillcolor="brown1",style="filled",style="filled",label="{OrigId: 13543580133643026784\n_Z1Fv -\> _Z1Dv}"]; 298; DOTCLONED: Node[[F]] -> Node[[D]][tooltip="ContextIds: 2",fillcolor="brown1"]; 299; DOTCLONED: Node[[C:0x[a-z0-9]+]] [shape=record,tooltip="N[[C]] ContextIds: 3",fillcolor="cyan",style="filled",style="filled",label="{OrigId: 0\n_Z1Cv -\> _Z1Dv}"]; 300; DOTCLONED: Node[[C]] -> Node[[D2:0x[a-z0-9]+]][tooltip="ContextIds: 3",fillcolor="cyan"]; 301; DOTCLONED: Node[[B:0x[a-z0-9]+]] [shape=record,tooltip="N[[B]] ContextIds: 4",fillcolor="cyan",style="filled",style="filled",label="{OrigId: 0\n_Z1Bv -\> _Z1Dv}"]; 302; DOTCLONED: Node[[B]] -> Node[[D2]][tooltip="ContextIds: 4",fillcolor="cyan"]; 303; DOTCLONED: Node[[E:0x[a-z0-9]+]] [shape=record,tooltip="N[[E]] ContextIds: 1",fillcolor="cyan",style="filled",style="filled",label="{OrigId: 0\n_Z1Ev -\> _Z1Dv}"]; 304; DOTCLONED: Node[[E]] -> Node[[D2]][tooltip="ContextIds: 1",fillcolor="cyan"]; 305; DOTCLONED: Node[[D2]] [shape=record,tooltip="N[[D2]] ContextIds: 1 3 4",fillcolor="cyan",style="filled",color="blue",style="filled,bold,dashed",label="{OrigId: Alloc0\n_Z1Dv -\> _Znam}"]; 306; DOTCLONED: } 307