brintos

brintos / llvm-project-archived public Read only

0
0
Text · 15.9 KiB · 6718711 Raw
276 lines · plain
1; RUN: opt %s -passes=sroa -S | FileCheck %s --check-prefixes=COMMON,OLD2; RUN: opt %s -passes=declare-to-assign,sroa -S | FileCheck %s --check-prefixes=COMMON,NEW3 4;; C++17 source:5;; struct two { int a, b; } gt;6;; int fun1() {7;;   auto [x, y] = gt;8;;   return x + y;9;; }10;;11;; struct four { two a, b; } gf;12;; int fun2() {13;;   auto [x, y] = gf;14;;   return x.a + y.b;15;; }16;; Plus some hand-written IR.17;;18;; Check that SROA understands how to split dbg.declares and dbg.assigns with19;; offsets into their storge (e.g., the second variable in a structured binding20;; is stored at an offset into the shared alloca).21;;22;; Additional notes:23;; We expect the same dbg.value intrinsics to come out of SROA whether assignment24;; tracking is enabled or not. However, the order of the debug intrinsics may25;; differ, and assignment tracking replaces some dbg.declares with dbg.assigns.26;;27;; Structured bindings produce an artificial variable that covers the entire28;; alloca. Although they add clutter to the test, they've been preserved in29;; order to increase coverage. These use the placehold name 'A' in comments and30;; checks.31 32%struct.two = type { i32, i32 }33%struct.four = type { %struct.two, %struct.two }34 35@gt = dso_local global %struct.two zeroinitializer, align 4, !dbg !036@gf = dso_local global %struct.four zeroinitializer, align 4, !dbg !537 38 39; COMMON-LABEL: @_Z4fun1v40; COMMON-NEXT: entry41;; 32 bit variable x (!27): value a_reg.42;;43;; 32 bit variable y (!28): value b_reg.44;;45;; 64 bit variable A (!29) bits [0,  32): value a_reg.46;; 64 bit variable A (!29) bits [32, 64): value b_reg.47 48; OLD-NEXT: %[[a_reg:.*]] = load i32, ptr @gt49; OLD-NEXT: #dbg_value(i32 %[[a_reg]], ![[x0:[0-9]+]], !DIExpression(),50; OLD-NEXT: #dbg_value(i32 %[[a_reg]], ![[A0:[0-9]+]], !DIExpression(DW_OP_LLVM_fragment, 0, 32),51; OLD-NEXT: %[[b_reg:.*]] = load i32, ptr getelementptr inbounds (i8, ptr @gt, i64 4)52; OLD-NEXT: #dbg_value(i32 %[[b_reg]], ![[y0:[0-9]+]], !DIExpression(),53; OLD-NEXT: #dbg_value(i32 %[[b_reg]], ![[A0]], !DIExpression(DW_OP_LLVM_fragment, 32, 32),54 55; NEW-NEXT: %[[a_reg:.*]] = load i32, ptr @gt56; NEW-NEXT: %[[b_reg:.*]] = load i32, ptr getelementptr inbounds (i8, ptr @gt, i64 4)57; NEW-NEXT: #dbg_value(i32 %[[b_reg]], ![[y0:[0-9]+]], !DIExpression(),58; NEW-NEXT: #dbg_value(i32 %[[a_reg]], ![[A0:[0-9]+]], !DIExpression(DW_OP_LLVM_fragment, 0, 32),59; NEW-NEXT: #dbg_value(i32 %[[b_reg]], ![[A0]], !DIExpression(DW_OP_LLVM_fragment, 32, 32),60; NEW-NEXT: #dbg_value(i32 %[[a_reg]], ![[x0:[0-9]+]], !DIExpression(),61define dso_local noundef i32 @_Z4fun1v() #0 !dbg !23 {62entry:63  %0 = alloca %struct.two, align 464    #dbg_declare(ptr %0, !27, !DIExpression(), !31)65    #dbg_declare(ptr %0, !28, !DIExpression(DW_OP_plus_uconst, 4), !31)66    #dbg_declare(ptr %0, !29, !DIExpression(), !31)67  call void @llvm.memcpy.p0.p0.i64(ptr align 4 %0, ptr align 4 @gt, i64 8, i1 false), !dbg !3168  %a = getelementptr inbounds %struct.two, ptr %0, i32 0, i32 0, !dbg !3169  %1 = load i32, ptr %a, align 4, !dbg !3170  %b = getelementptr inbounds %struct.two, ptr %0, i32 0, i32 1, !dbg !3171  %2 = load i32, ptr %b, align 4, !dbg !3172  %add = add nsw i32 %1, %2, !dbg !3173  ret i32 %add, !dbg !3174}75 76; COMMON-LABEL: _Z4fun2v()77; COMMON-NEXT: entry:78;; 64 bit variable x (!50) bits [0,  32): value aa_reg.79;; 64 bit variable x (!50) bits [32, 64): deref ab_ba_addr80;;81;; 64 bit variable y (!51) bits [0,  32): deref ab_ba_addr + 3282;; 64 bit variable y (!51) bits [32, 64): value bb_reg.83;;84;; 128 bit variable A (!52) bits [0,   32): value aa_reg85;; 128 bit variable A (!52) bits [32,  64): deref ab_ba_addr86;; 128 bit variable A (!52) bits [96, 128): value bb_reg87;;88;; NOTE: This 8 byte alloca contains x.b (4 bytes) and y.a (4 bytes).89; COMMON-NEXT: %[[ab_ba_addr:.*]] = alloca [8 x i8], align 490; OLD-NEXT: #dbg_declare(ptr %[[ab_ba_addr]], ![[A1:[0-9]+]], !DIExpression(DW_OP_LLVM_fragment, 32, 64),91; OLD-NEXT: #dbg_declare(ptr %[[ab_ba_addr]], ![[y1:[0-9]+]], !DIExpression(DW_OP_plus_uconst, 4, DW_OP_LLVM_fragment, 0, 32),92; OLD-NEXT: #dbg_declare(ptr %[[ab_ba_addr]], ![[x1:[0-9]+]], !DIExpression(DW_OP_LLVM_fragment, 32, 32),93; OLD-NEXT: %[[aa_reg:.*]] = load i32, ptr @gf, align 494; OLD-NEXT: #dbg_value(i32 %[[aa_reg]], ![[x1]], !DIExpression(DW_OP_LLVM_fragment, 0, 32),95; OLD-NEXT: #dbg_value(i32 %[[aa_reg]], ![[A1]], !DIExpression(DW_OP_LLVM_fragment, 0, 32),96; OLD-NEXT: call void @llvm.memcpy{{.*}}(ptr align 4 %[[ab_ba_addr]], ptr align 4 getelementptr inbounds (i8, ptr @gf, i64 4), i64 8, i1 false)97; OLD-NEXT: %[[bb_reg:.*]] = load i32, ptr getelementptr inbounds (i8, ptr @gf, i64 12), align 498; OLD-NEXT: #dbg_value(i32 %[[bb_reg]], ![[y1]], !DIExpression(DW_OP_LLVM_fragment, 32, 32),99; OLD-NEXT: #dbg_value(i32 %[[bb_reg]], ![[A1]], !DIExpression(DW_OP_LLVM_fragment, 96, 32),100 101; NEW-NEXT: #dbg_assign(i1 poison, ![[x1:[0-9]+]], !DIExpression(DW_OP_LLVM_fragment, 32, 32), ![[#]], ptr %[[ab_ba_addr]], !DIExpression(),102; NEW-NEXT: #dbg_assign(i1 poison, ![[A1:[0-9]+]], !DIExpression(DW_OP_LLVM_fragment, 32, 64), ![[#]], ptr %[[ab_ba_addr]], !DIExpression(),103; NEW-NEXT: #dbg_declare(ptr %[[ab_ba_addr]], ![[y1:[0-9]+]], !DIExpression(DW_OP_plus_uconst, 4, DW_OP_LLVM_fragment, 0, 32),104; NEW-NEXT: %[[aa_reg:.*]] = load i32, ptr @gf, align 4105; NEW-NEXT: llvm.memcpy{{.*}}(ptr align 4 %[[ab_ba_addr]], ptr align 4 getelementptr inbounds (i8, ptr @gf, i64 4), i64 8, i1 false){{.*}}, !DIAssignID ![[ID:[0-9]+]]106; NEW-NEXT: %[[bb_reg:.*]] = load i32, ptr getelementptr inbounds (i8, ptr @gf, i64 12), align 4107; NEW-NEXT: #dbg_value(i32 %[[bb_reg]], ![[y1:[0-9]+]], !DIExpression(DW_OP_LLVM_fragment, 32, 32),108; NEW-NEXT: #dbg_value(i32 %[[aa_reg]], ![[A1]], !DIExpression(DW_OP_LLVM_fragment, 0, 32),109; NEW-NEXT: #dbg_assign(i1 poison, ![[A1]], !DIExpression(DW_OP_LLVM_fragment, 32, 64), ![[ID]], ptr %[[ab_ba_addr]], !DIExpression(),110; NEW-NEXT: #dbg_value(i32 %[[bb_reg]], ![[A1]], !DIExpression(DW_OP_LLVM_fragment, 96, 32),111; NEW-NEXT: #dbg_value(i32 %[[aa_reg]], ![[x1]], !DIExpression(DW_OP_LLVM_fragment, 0, 32),112define dso_local noundef i32 @_Z4fun2v() #0 !dbg !48 {113entry:114  %0 = alloca %struct.four, align 4115    #dbg_declare(ptr %0, !50, !DIExpression(), !54)116    #dbg_declare(ptr %0, !51, !DIExpression(DW_OP_plus_uconst, 8), !54)117    #dbg_declare(ptr %0, !52, !DIExpression(), !54)118  call void @llvm.memcpy.p0.p0.i64(ptr align 4 %0, ptr align 4 @gf, i64 16, i1 false), !dbg !54119  %a = getelementptr inbounds %struct.four, ptr %0, i32 0, i32 0, !dbg !54120  %a1 = getelementptr inbounds %struct.two, ptr %a, i32 0, i32 0, !dbg !54121  %1 = load i32, ptr %a1, align 4, !dbg !54122  %b = getelementptr inbounds %struct.four, ptr %0, i32 0, i32 1, !dbg !54123  %b2 = getelementptr inbounds %struct.two, ptr %b, i32 0, i32 1, !dbg !54124  %2 = load i32, ptr %b2, align 4, !dbg !54125  %add = add nsw i32 %1, %2, !dbg !54126  ret i32 %add, !dbg !54127}128 129;; Hand-written part to test what happens when variables are smaller than the130;; new alloca slices (i.e., check offset rewriting works correctly). Note that131;; mem2reg incorrectly preserves the offest in the DIExpression of a variable132;; stuffed into the upper bits of a value (that is a bug), e.g. alloca+offset133;; becomes vreg+offest. It should either convert the offest to a shift, encode134;; the register-bit offest using DW_OP_bit_piece, or use the new135;; DW_OP_LLVM_extract_bits_[sz]ext operation.136; COMMON-LABEL: _Z4fun3v()137; COMMON-NEXT: entry:138;; 16 bit variable e (!61): value ve (upper bits)139;;140;; 16 bit variable f (!62): value vgf (lower bits)141;; 16 bit variable g (!63): value vgf (upper bits)142;;143;; 16 bit variable h (!64): deref dead_64_128144; COMMON-NEXT: %[[dead_64_128:.*]] = alloca %struct.two145; COMMON-NEXT: #dbg_declare(ptr %[[dead_64_128]], ![[h:[0-9]+]], !DIExpression(),146; COMMON-NEXT: %[[ve:.*]] = load i32, ptr @gf147;; FIXME: mem2reg bug - offset is incorrect - see comment above.148; COMMON-NEXT: #dbg_value(i32 %[[ve]], ![[e:[0-9]+]], !DIExpression(DW_OP_plus_uconst, 2),149; COMMON-NEXT: %[[vfg:.*]] = load i32, ptr getelementptr inbounds (i8, ptr @gf, i64 4)150; COMMON-NEXT: #dbg_value(i32 %[[vfg]], ![[f:[0-9]+]], !DIExpression(),151;; FIXME: mem2reg bug - offset is incorrect - see comment above.152; COMMON-NEXT: #dbg_value(i32 %[[vfg]], ![[g:[0-9]+]], !DIExpression(DW_OP_plus_uconst, 2),153define dso_local noundef i32 @_Z4fun3v() #0 !dbg !55 {154entry:155  %0 = alloca %struct.four, align 4156    #dbg_declare(ptr %0, !61, !DIExpression(DW_OP_plus_uconst, 2), !58)157    #dbg_declare(ptr %0, !62, !DIExpression(DW_OP_plus_uconst, 4), !58)158    #dbg_declare(ptr %0, !63, !DIExpression(DW_OP_plus_uconst, 6), !58)159    #dbg_declare(ptr %0, !64, !DIExpression(DW_OP_plus_uconst, 8), !58)160  call void @llvm.memcpy.p0.p0.i64(ptr align 4 %0, ptr align 4 @gf, i64 16, i1 false), !dbg !58161  %1 = getelementptr inbounds %struct.four, ptr %0, i32 0, i32 0, !dbg !58162  %2 = getelementptr inbounds %struct.two, ptr %1, i32 0, i32 1, !dbg !58163  %3 = load i32, ptr %2, align 4, !dbg !58164  ret i32 %3, !dbg !58165}166 167;; Check that DW_OP_extract_bits_[sz]ext compose with expression offsets and168;; that new fragments are not created. DW_OP_extract_bits_[sz]ext and fragments169;; don't compose currently (but could). There are checks that expressions with170;; bit extracts and fragments are dropped in SROA the test171;; in llvm/test/DebugInfo/Generic/sroa-extract-bits.ll. FIXME: Don't do that.172;;173;; Checks are inline for this one.174;;175;; %p alloca is 128 bits176;; SROA is going to split it in half, discard the lower bits, then split177;; the upper bits in half and discard the upper bits leaving us with178;; bits [64, 96) of the original alloca.179;;180; COMMON-LABEL: fun4181define dso_local noundef i32 @fun4(i64 %0) !dbg !65 {182entry:183  %p = alloca [2 x i64]184  %1 = getelementptr inbounds [2 x i64], ptr %p, i32 0, i32 1185  store i64 %0, ptr %1186  ; COMMON: %p.sroa.0.8.extract.trunc = trunc i64 %0 to i32187  ;; Simple case - the expression offset (8 bytes) matches the offset of the188  ;; slice into the alloca, so can be discarded away entirely.189  ; COMMON-NEXT: #dbg_value(i32 %p.sroa.0.8.extract.trunc, ![[p:[0-9]+]], !DIExpression(DW_OP_LLVM_extract_bits_zext, 0, 32)190    #dbg_declare(ptr %p, !67, !DIExpression(DW_OP_plus_uconst, 8, DW_OP_LLVM_extract_bits_zext, 0, 32), !66)191  ;; The expression offset is 6 bytes, with a bit-extract offset of 32 bits from192  ;; there for a total offset of 80 bits. SROA is going to split the alloca in193  ;; half (at bit 64). The new expression needs a final bit extract offset of194  ;; 80-64=16 bits applied to the mem2reg'd value.195  ; COMMON-NEXT: #dbg_value(i32 %p.sroa.0.8.extract.trunc, ![[q:[0-9]+]], !DIExpression(DW_OP_LLVM_extract_bits_zext, 16, 8)196    #dbg_declare(ptr %p, !68, !DIExpression(DW_OP_plus_uconst, 6, DW_OP_LLVM_extract_bits_zext, 32, 8), !66)197  ;; FIXME: Just as in _Z4fun3v, the offset from the new alloca (2 bytes) is198  ;; correct but mem2reg needs to change it from an offset to a shift or199  ;; adjust the bit-extract (e.g., add the 2 byte offset to the existing 8 bit200  ;; offset for a 24 bit total bit-extract offset).201  ; COMMON-NEXT: #dbg_value(i32 %p.sroa.0.8.extract.trunc, ![[r:[0-9]+]], !DIExpression(DW_OP_plus_uconst, 2, DW_OP_LLVM_extract_bits_zext, 8, 8)202    #dbg_declare(ptr %p, !69, !DIExpression(DW_OP_plus_uconst, 10, DW_OP_LLVM_extract_bits_zext, 8, 8), !66)203  %2 = load i32, ptr %1, align 4204  ret i32 %2205}206 207; COMMON-DAG: ![[x0]] = !DILocalVariable(name: "x",208; COMMON-DAG: ![[y0]] = !DILocalVariable(name: "y",209; COMMON-DAG: ![[A0]] = !DILocalVariable(scope:210 211; COMMON-DAG: ![[x1]] = !DILocalVariable(name: "x",212; COMMON-DAG: ![[y1]] = !DILocalVariable(name: "y",213; COMMON-DAG: ![[A1]] = !DILocalVariable(scope:214 215; COMMON-DAG: ![[e]] = !DILocalVariable(name: "e",216; COMMON-DAG: ![[f]] = !DILocalVariable(name: "f",217; COMMON-DAG: ![[g]] = !DILocalVariable(name: "g",218; COMMON-DAG: ![[h]] = !DILocalVariable(name: "h",219 220; COMMON-DAG: ![[p]] = !DILocalVariable(name: "p"221; COMMON-DAG: ![[q]] = !DILocalVariable(name: "q"222; COMMON-DAG: ![[r]] = !DILocalVariable(name: "r"223 224declare void @llvm.memcpy.p0.p0.i64(ptr noalias nocapture writeonly, ptr noalias nocapture readonly, i64, i1 immarg)225 226!llvm.dbg.cu = !{!2}227!llvm.module.flags = !{!16, !17}228!llvm.ident = !{!22}229 230!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())231!1 = distinct !DIGlobalVariable(name: "gt", scope: !2, file: !3, line: 1, type: !10, isLocal: false, isDefinition: true)232!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, producer: "clang version 17.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None)233!3 = !DIFile(filename: "test.cpp", directory: "/")234!4 = !{!0, !5}235!5 = !DIGlobalVariableExpression(var: !6, expr: !DIExpression())236!6 = distinct !DIGlobalVariable(name: "gf", scope: !2, file: !3, line: 7, type: !7, isLocal: false, isDefinition: true)237!7 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "four", file: !3, line: 7, size: 128, flags: DIFlagTypePassByValue, elements: !8, identifier: "_ZTS4four")238!8 = !{!9, !15}239!9 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !7, file: !3, line: 7, baseType: !10, size: 64)240!10 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "two", file: !3, line: 1, size: 64, flags: DIFlagTypePassByValue, elements: !11, identifier: "_ZTS3two")241!11 = !{!12, !14}242!12 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !10, file: !3, line: 1, baseType: !13, size: 32)243!13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)244!14 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !10, file: !3, line: 1, baseType: !13, size: 32, offset: 32)245!15 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !7, file: !3, line: 7, baseType: !10, size: 64, offset: 64)246!16 = !{i32 7, !"Dwarf Version", i32 5}247!17 = !{i32 2, !"Debug Info Version", i32 3}248!22 = !{!"clang version 17.0.0"}249!23 = distinct !DISubprogram(name: "fun1", linkageName: "_Z4fun1v", scope: !3, file: !3, line: 2, type: !24, scopeLine: 2, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !26)250!24 = !DISubroutineType(types: !25)251!25 = !{!13}252!26 = !{!27, !28, !29}253!27 = !DILocalVariable(name: "x", scope: !23, file: !3, line: 3, type: !13)254!28 = !DILocalVariable(name: "y", scope: !23, file: !3, line: 3, type: !13)255!29 = !DILocalVariable(scope: !23, file: !3, line: 3, type: !10)256!31 = !DILocation(line: 3, column: 9, scope: !23)257!48 = distinct !DISubprogram(name: "fun2", linkageName: "_Z4fun2v", scope: !3, file: !3, line: 8, type: !24, scopeLine: 8, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !49)258!49 = !{!50, !51, !52}259!50 = !DILocalVariable(name: "x", scope: !48, file: !3, line: 9, type: !10)260!51 = !DILocalVariable(name: "y", scope: !48, file: !3, line: 9, type: !10)261!52 = !DILocalVariable(scope: !48, file: !3, line: 9, type: !7)262!54 = !DILocation(line: 9, column: 9, scope: !48)263!55 = distinct !DISubprogram(name: "fun3", linkageName: "_Z4fun3v", scope: !3, file: !3, line: 8, type: !24, scopeLine: 8, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !56)264!56 = !{}265!58 = !DILocation(line: 9, column: 9, scope: !55)266!60 = !DIBasicType(name: "short", size: 16, encoding: DW_ATE_signed)267!61 = !DILocalVariable(name: "e", scope: !55, file: !3, line: 9, type: !60)268!62 = !DILocalVariable(name: "f", scope: !55, file: !3, line: 9, type: !60)269!63 = !DILocalVariable(name: "g", scope: !55, file: !3, line: 9, type: !60)270!64 = !DILocalVariable(name: "h", scope: !55, file: !3, line: 9, type: !60)271!65 = distinct !DISubprogram(name: "fun4", linkageName: "_Z4fun4v", scope: !3, file: !3, line: 8, type: !24, scopeLine: 8, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !56)272!66 = !DILocation(line: 9, column: 9, scope: !65)273!67 = !DILocalVariable(name: "p", scope: !65, file: !3, line: 9, type: !13)274!68 = !DILocalVariable(name: "q", scope: !65, file: !3, line: 9, type: !13)275!69 = !DILocalVariable(name: "r", scope: !65, file: !3, line: 9, type: !13)276