1; This file contains some of the same basic tests as statepoint-vreg.ll, but 2; focuses on examining the intermediate representation. It's separate so that 3; the main file is easy to update with update_llc_test_checks.py 4 5; This run is to demonstrate what MIR SSA looks like. 6; RUN: llc -max-registers-for-gc-values=4 -stop-after finalize-isel < %s | FileCheck --check-prefix=CHECK-VREG %s 7; This run is to demonstrate register allocator work. 8; RUN: llc -max-registers-for-gc-values=4 -stop-after virtregrewriter < %s | FileCheck --check-prefix=CHECK-PREG %s 9 10target datalayout = "e-i64:64-f80:128-n8:16:32:64-S128" 11target triple = "x86_64-pc-linux-gnu" 12 13declare dso_local i1 @return_i1() 14declare dso_local void @func() 15declare dso_local void @consume(i32 addrspace(1)*) 16declare dso_local void @consume2(i32 addrspace(1)*, i32 addrspace(1)*) 17declare dso_local void @consume5(i32 addrspace(1)*, i32 addrspace(1)*, i32 addrspace(1)*, i32 addrspace(1)*, i32 addrspace(1)*) 18declare dso_local void @use1(i32 addrspace(1)*, i8 addrspace(1)*) 19declare dso_local i32* @fake_personality_function() 20declare dso_local i32 @foo(i32, i8 addrspace(1)*, i32, i32, i32) 21declare dso_local void @bar(i8 addrspace(1)*, i8 addrspace(1)*) 22 23; test most simple relocate 24define i1 @test_relocate(i32 addrspace(1)* %a) gc "statepoint-example" { 25; CHECK-VREG-LABEL: name: test_relocate 26; CHECK-VREG: %0:gr64 = COPY $rdi 27; CHECK-VREG: %1:gr64 = STATEPOINT 0, 0, 0, @return_i1, 2, 0, 2, 0, 2, 0, 2, 1, %0(tied-def 0), 2, 0, 2, 1, 0, 0, csr_64, implicit-def $rsp, implicit-def $ssp, implicit-def $al 28; CHECK-VREG: %2:gr8 = COPY $al 29; CHECK-VREG: $rdi = COPY %1 30; CHECK-VREG: CALL64pcrel32 @consume, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp 31 32; CHECK-PREG-LABEL: name: test_relocate 33; CHECK-PREG: renamable $rbx = COPY $rdi 34; CHECK-PREG: renamable $rbx = STATEPOINT 0, 0, 0, @return_i1, 2, 0, 2, 0, 2, 0, 2, 1, killed renamable $rbx(tied-def 0), 2, 0, 2, 1, 0, 0, csr_64, implicit-def $rsp, implicit-def $ssp, implicit-def $al 35; CHECK-PREG: renamable $bpl = COPY killed $al 36; CHECK-PREG: $rdi = COPY killed renamable $rbx 37; CHECK-PREG: CALL64pcrel32 @consume, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp 38 39entry: 40 %safepoint_token = tail call token (i64, i32, i1 ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_i1f(i64 0, i32 0, i1 ()* @return_i1, i32 0, i32 0, i32 0, i32 0) ["gc-live" (i32 addrspace(1)* %a)] 41 %rel1 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token, i32 0, i32 0) 42 %res1 = call zeroext i1 @llvm.experimental.gc.result.i1(token %safepoint_token) 43 call void @consume(i32 addrspace(1)* %rel1) 44 ret i1 %res1 45} 46; test pointer variables intermixed with pointer constants 47define void @test_mixed(i32 addrspace(1)* %a, i32 addrspace(1)* %b, i32 addrspace(1)* %c) gc "statepoint-example" { 48; CHECK-VREG-LABEL: name: test_mixed 49; CHECK-VREG: %2:gr64 = COPY $rdx 50; CHECK-VREG: %1:gr64 = COPY $rsi 51; CHECK-VREG: %0:gr64 = COPY $rdi 52; CHECK-VREG: %3:gr64, %4:gr64, %5:gr64 = STATEPOINT 0, 0, 0, @func, 2, 0, 2, 0, 2, 0, 2, 4, %2(tied-def 0), 2, 0, %1(tied-def 1), %0(tied-def 2), 2, 0, 2, 4, 0, 0, 1, 1, 2, 2, 3, 3, csr_64, implicit-def $rsp, implicit-def $ssp 53; CHECK-VREG: %6:gr32 = MOV32r0 implicit-def dead $eflags 54; CHECK-VREG: %7:gr64 = SUBREG_TO_REG 0, killed %6, %subreg.sub_32bit 55; CHECK-VREG: $rdi = COPY %5 56; CHECK-VREG: $rsi = COPY %7 57; CHECK-VREG: $rdx = COPY %4 58; CHECK-VREG: $rcx = COPY %7 59; CHECK-VREG: $r8 = COPY %3 60; CHECK-VREG: CALL64pcrel32 @consume5, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit $rsi, implicit $rdx, implicit $rcx, implicit $r8, implicit-def $rsp, implicit-def $ssp 61 62; CHECK-PREG-LABEL: name: test_mixed 63; CHECK-PREG: renamable $r14 = COPY $rdx 64; CHECK-PREG: renamable $r15 = COPY $rsi 65; CHECK-PREG: renamable $rbx = COPY $rdi 66; CHECK-PREG: renamable $r14, renamable $r15, renamable $rbx = STATEPOINT 0, 0, 0, @func, 2, 0, 2, 0, 2, 0, 2, 4, killed renamable $r14(tied-def 0), 2, 0, killed renamable $r15(tied-def 1), killed renamable $rbx(tied-def 2), 2, 0, 2, 4, 0, 0, 1, 1, 2, 2, 3, 3, csr_64, implicit-def $rsp, implicit-def $ssp 67; CHECK-PREG: $rdi = COPY killed renamable $rbx 68; CHECK-PREG: dead $esi = MOV32r0 implicit-def dead $eflags, implicit-def $rsi 69; CHECK-PREG: $rdx = COPY killed renamable $r15 70; CHECK-PREG: dead $ecx = MOV32r0 implicit-def dead $eflags, implicit-def $rcx 71; CHECK-PREG: $r8 = COPY killed renamable $r14 72; CHECK-PREG: CALL64pcrel32 @consume5, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit $rsi, implicit $rdx, implicit killed $rcx, implicit killed $r8, implicit-def $rsp, implicit-def $ssp 73 74entry: 75 %safepoint_token = tail call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @func, i32 0, i32 0, i32 0, i32 0) ["gc-live" (i32 addrspace(1)* %a, i32 addrspace(1)* null, i32 addrspace(1)* %b, i32 addrspace(1)* null, i32 addrspace(1)* %c)] 76 %rel1 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token, i32 0, i32 0) 77 %rel2 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token, i32 1, i32 1) 78 %rel3 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token, i32 2, i32 2) 79 %rel4 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token, i32 3, i32 3) 80 %rel5 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token, i32 4, i32 4) 81 call void @consume5(i32 addrspace(1)* %rel1, i32 addrspace(1)* %rel2, i32 addrspace(1)* %rel3, i32 addrspace(1)* %rel4, i32 addrspace(1)* %rel5) 82 ret void 83} 84 85; same as above, but for alloca 86define i32 addrspace(1)* @test_alloca(i32 addrspace(1)* %ptr) gc "statepoint-example" { 87; CHECK-VREG-LABEL: name: test_alloca 88; CHECK-VREG: %0:gr64 = COPY $rdi 89; CHECK-VREG: MOV64mr %stack.0.alloca, 1, $noreg, 0, $noreg, %0 :: (store 8 into %ir.alloca) 90; CHECK-VREG: %1:gr64 = STATEPOINT 0, 0, 0, @return_i1, 2, 0, 2, 0, 2, 0, 2, 1, %0(tied-def 0), 2, 1, 0, %stack.0.alloca, 0, 2, 1, 0, 0, csr_64, implicit-def $rsp, implicit-def $ssp, implicit-def $al :: (volatile load store 8 on %stack.0.alloca) 91; CHECK-VREG: %2:gr8 = COPY $al 92; CHECK-VREG: %3:gr64 = MOV64rm %stack.0.alloca, 1, $noreg, 0, $noreg :: (dereferenceable load 8 from %ir.alloca) 93; CHECK-VREG: $rdi = COPY %1 94; CHECK-VREG: CALL64pcrel32 @consume, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp 95 96; CHECK-PREG-LABEL: name: test_alloca 97; CHECK-PREG: renamable $rbx = COPY $rdi 98; CHECK-PREG: MOV64mr %stack.0.alloca, 1, $noreg, 0, $noreg, renamable $rbx :: (store 8 into %ir.alloca) 99; CHECK-PREG: renamable $rbx = STATEPOINT 0, 0, 0, @return_i1, 2, 0, 2, 0, 2, 0, 2, 1, killed renamable $rbx(tied-def 0), 2, 1, 0, %stack.0.alloca, 0, 2, 1, 0, 0, csr_64, implicit-def $rsp, implicit-def $ssp, implicit-def dead $al :: (volatile load store 8 on %stack.0.alloca) 100; CHECK-PREG: renamable $r14 = MOV64rm %stack.0.alloca, 1, $noreg, 0, $noreg :: (dereferenceable load 8 from %ir.alloca) 101; CHECK-PREG: $rdi = COPY killed renamable $rbx 102; CHECK-PREG: CALL64pcrel32 @consume, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp 103 104entry: 105 %alloca = alloca i32 addrspace(1)*, align 8 106 store i32 addrspace(1)* %ptr, i32 addrspace(1)** %alloca 107 %safepoint_token = call token (i64, i32, i1 ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_i1f(i64 0, i32 0, i1 ()* @return_i1, i32 0, i32 0, i32 0, i32 0) ["gc-live" (i32 addrspace(1)** %alloca, i32 addrspace(1)* %ptr)] 108 %rel1 = load i32 addrspace(1)*, i32 addrspace(1)** %alloca 109 %rel2 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token, i32 1, i32 1) 110 call void @consume(i32 addrspace(1)* %rel2) 111 ret i32 addrspace(1)* %rel1 112} 113 114; test base != derived 115define void @test_base_derived(i32 addrspace(1)* %base, i32 addrspace(1)* %derived) gc "statepoint-example" { 116; CHECK-VREG-LABEL: name: test_base_derived 117; CHECK-VREG: %1:gr64 = COPY $rsi 118; CHECK-VREG: %0:gr64 = COPY $rdi 119; CHECK-VREG: %2:gr64, %3:gr64 = STATEPOINT 0, 0, 0, @func, 2, 0, 2, 0, 2, 0, 2, 2, %1(tied-def 0), %0(tied-def 1), 2, 0, 2, 1, 1, 0, csr_64, implicit-def $rsp, implicit-def $ssp 120; CHECK-VREG: $rdi = COPY %2 121; CHECK-VREG: CALL64pcrel32 @consume, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp 122 123; CHECK-PREG-LABEL: name: test_base_derived 124; CHECK-PREG: renamable $rbx = COPY $rsi 125; CHECK-PREG: renamable $rbx, dead renamable $r14 = STATEPOINT 0, 0, 0, @func, 2, 0, 2, 0, 2, 0, 2, 2, killed renamable $rbx(tied-def 0), killed renamable $r14(tied-def 1), 2, 0, 2, 1, 1, 0, csr_64, implicit-def $rsp, implicit-def $ssp 126; CHECK-PREG: $rdi = COPY killed renamable $rbx 127; CHECK-PREG: CALL64pcrel32 @consume, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp 128 129 %safepoint_token = tail call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @func, i32 0, i32 0, i32 0, i32 0) ["gc-live" (i32 addrspace(1)* %base, i32 addrspace(1)* %derived)] 130 %reloc = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token, i32 0, i32 1) 131 call void @consume(i32 addrspace(1)* %reloc) 132 ret void 133} 134 135; deopt GC pointer not present in GC args must be spilled 136define void @test_deopt_gcpointer(i32 addrspace(1)* %a, i32 addrspace(1)* %b) gc "statepoint-example" { 137; CHECK-VREG-LABEL: name: test_deopt_gcpointer 138; CHECK-VREG: %1:gr64 = COPY $rsi 139; CHECK-VREG: %0:gr64 = COPY $rdi 140; CHECK-VREG: MOV64mr %stack.0, 1, $noreg, 0, $noreg, %0 :: (store 8 into %stack.0) 141; CHECK-VREG: %2:gr64 = STATEPOINT 0, 0, 0, @func, 2, 0, 2, 0, 2, 1, 1, 8, %stack.0, 0, 2, 1, %1(tied-def 0), 2, 0, 2, 1, 0, 0, csr_64, implicit-def $rsp, implicit-def $ssp :: (volatile load store 8 on %stack.0) 142; CHECK-VREG: $rdi = COPY %2 143; CHECK-VREG: CALL64pcrel32 @consume, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp 144; CHECK-VREG: RET 0 145 146; CHECK-PREG-LABEL: name: test_deopt_gcpointer 147; CHECK-PREG: renamable $rbx = COPY $rsi 148; CHECK-PREG: MOV64mr %stack.0, 1, $noreg, 0, $noreg, killed renamable $rdi :: (store 8 into %stack.0) 149; CHECK-PREG: renamable $rbx = STATEPOINT 0, 0, 0, @func, 2, 0, 2, 0, 2, 1, 1, 8, %stack.0, 0, 2, 1, killed renamable $rbx(tied-def 0), 2, 0, 2, 1, 0, 0, csr_64, implicit-def $rsp, implicit-def $ssp :: (volatile load store 8 on %stack.0) 150; CHECK-PREG: $rdi = COPY killed renamable $rbx 151; CHECK-PREG: CALL64pcrel32 @consume, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp 152 153 %safepoint_token = tail call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @func, i32 0, i32 0, i32 0, i32 0) ["deopt" (i32 addrspace(1)* %a), "gc-live" (i32 addrspace(1)* %b)] 154 %rel = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token, i32 0, i32 0) 155 call void @consume(i32 addrspace(1)* %rel) 156 ret void 157} 158 159;; Two gc.relocates of the same input, should require only a single spill/fill 160define void @test_gcrelocate_uniqueing(i32 addrspace(1)* %ptr) gc "statepoint-example" { 161; CHECK-VREG-LABEL: name: test_gcrelocate_uniqueing 162; CHECK-VREG: %0:gr64 = COPY $rdi 163; CHECK-VREG: %1:gr64 = STATEPOINT 0, 0, 0, @func, 2, 0, 2, 0, 2, 2, %0, 2, 4278124286, 2, 1, %0(tied-def 0), 2, 0, 2, 1, 0, 0, csr_64, implicit-def $rsp, implicit-def $ssp 164; CHECK-VREG: $rdi = COPY %1 165; CHECK-VREG: $rsi = COPY %1 166; CHECK-VREG: CALL64pcrel32 @consume2, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit $rsi, implicit-def $rsp, implicit-def $ssp 167 168; CHECK-PREG-LABEL: name: test_gcrelocate_uniqueing 169; CHECK-PREG: renamable $rbx = COPY $rdi 170; CHECK-PREG: renamable $rbx = STATEPOINT 0, 0, 0, @func, 2, 0, 2, 0, 2, 2, killed renamable $rbx, 2, 4278124286, 2, 1, renamable $rbx(tied-def 0), 2, 0, 2, 1, 0, 0, csr_64, implicit-def $rsp, implicit-def $ssp 171; CHECK-PREG: $rdi = COPY renamable $rbx 172; CHECK-PREG: $rsi = COPY killed renamable $rbx 173; CHECK-PREG: CALL64pcrel32 @consume2, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit killed $rsi, implicit-def $rsp, implicit-def $ssp 174 175 %tok = tail call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @func, i32 0, i32 0, i32 0, i32 0) ["deopt" (i32 addrspace(1)* %ptr, i32 undef), "gc-live" (i32 addrspace(1)* %ptr, i32 addrspace(1)* %ptr)] 176 %a = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %tok, i32 0, i32 0) 177 %b = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %tok, i32 1, i32 1) 178 call void @consume2(i32 addrspace(1)* %a, i32 addrspace(1)* %b) 179 ret void 180} 181 182; Two gc.relocates of a bitcasted pointer should only require a single spill/fill 183define void @test_gcptr_uniqueing(i32 addrspace(1)* %ptr) gc "statepoint-example" { 184; CHECK-VREG-LABEL: name: test_gcptr_uniqueing 185; CHECK-VREG: %0:gr64 = COPY $rdi 186; CHECK-VREG: ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp 187; CHECK-VREG: %1:gr64 = STATEPOINT 0, 0, 0, @func, 2, 0, 2, 0, 2, 2, %0, 2, 4278124286, 2, 1, %0(tied-def 0), 2, 0, 2, 1, 0, 0, csr_64, implicit-def $rsp, implicit-def $ssp 188; CHECK-VREG: ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp 189; CHECK-VREG: ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp 190; CHECK-VREG: $rdi = COPY %1 191; CHECK-VREG: $rsi = COPY %1 192; CHECK-VREG: CALL64pcrel32 @use1, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit $rsi, implicit-def $rsp, implicit-def $ssp 193 194; CHECK-PREG-LABEL: name: test_gcptr_uniqueing 195; CHECK-PREG: renamable $rbx = COPY $rdi 196; CHECK-PREG: renamable $rbx = STATEPOINT 0, 0, 0, @func, 2, 0, 2, 0, 2, 2, killed renamable $rbx, 2, 4278124286, 2, 1, renamable $rbx(tied-def 0), 2, 0, 2, 1, 0, 0, csr_64, implicit-def $rsp, implicit-def $ssp 197; CHECK-PREG: $rdi = COPY renamable $rbx 198; CHECK-PREG: $rsi = COPY killed renamable $rbx 199; CHECK-PREG: CALL64pcrel32 @use1, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit killed $rsi, implicit-def $rsp, implicit-def $ssp 200 201 %ptr2 = bitcast i32 addrspace(1)* %ptr to i8 addrspace(1)* 202 %tok = tail call token (i64, i32, void ()*, i32, i32, ...) 203 @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @func, i32 0, i32 0, i32 0, i32 0) ["deopt" (i32 addrspace(1)* %ptr, i32 undef), "gc-live" (i32 addrspace(1)* %ptr, i8 addrspace(1)* %ptr2)] 204 %a = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %tok, i32 0, i32 0) 205 %b = call i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(token %tok, i32 1, i32 1) 206 call void @use1(i32 addrspace(1)* %a, i8 addrspace(1)* %b) 207 ret void 208} 209 210define i1 @test_cross_bb(i32 addrspace(1)* %a, i1 %external_cond) gc "statepoint-example" { 211; CHECK-VREG-LABEL: name: test_cross_bb 212; CHECK-VREG: bb.0.entry: 213; CHECK-VREG: %1:gr32 = COPY $esi 214; CHECK-VREG-NEXT: %0:gr64 = COPY $rdi 215; CHECK-VREG-NEXT: %4:gr8 = COPY %1.sub_8bit 216; CHECK-VREG-NEXT: ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp 217; CHECK-VREG-NEXT: %2:gr64 = STATEPOINT 0, 0, 0, @return_i1, 2, 0, 2, 0, 2, 0, 2, 1, %0(tied-def 0), 2, 0, 2, 1, 0, 0, csr_64, implicit-def $rsp, implicit-def $ssp, implicit-def $al 218; CHECK-VREG-NEXT: ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp 219; CHECK-VREG-NEXT: %5:gr8 = COPY $al 220; CHECK-VREG-NEXT: %3:gr8 = COPY %5 221; CHECK-VREG-NEXT: TEST8ri killed %4, 1, implicit-def $eflags 222; CHECK-VREG-NEXT: JCC_1 %bb.2, 4, implicit $eflags 223; CHECK-VREG-NEXT: JMP_1 %bb.1 224; CHECK-VREG: bb.1.left: 225; CHECK-VREG-NEXT: ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp 226; CHECK-VREG-NEXT: $rdi = COPY %2 227; CHECK-VREG-NEXT: CALL64pcrel32 @consume, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp 228; CHECK-VREG-NEXT: ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp 229; CHECK-VREG-NEXT: $al = COPY %3 230; CHECK-VREG-NEXT: RET 0, $al 231; CHECK-VREG: bb.2.right: 232; CHECK-VREG-NEXT: %6:gr8 = MOV8ri 1 233; CHECK-VREG-NEXT: $al = COPY %6 234; CHECK-VREG-NEXT: RET 0, $al 235 236entry: 237 %safepoint_token = tail call token (i64, i32, i1 ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_i1f(i64 0, i32 0, i1 ()* @return_i1, i32 0, i32 0, i32 0, i32 0) ["gc-live" (i32 addrspace(1)* %a)] 238 br i1 %external_cond, label %left, label %right 239 240left: 241 %call1 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token, i32 0, i32 0) 242 %call2 = call zeroext i1 @llvm.experimental.gc.result.i1(token %safepoint_token) 243 call void @consume(i32 addrspace(1)* %call1) 244 ret i1 %call2 245 246right: 247 ret i1 true 248} 249 250; No need to check post-regalloc output as it is the same 251define i1 @duplicate_reloc() gc "statepoint-example" { 252; CHECK-VREG-LABEL: name: duplicate_reloc 253; CHECK-VREG: bb.0.entry: 254; CHECK-VREG: STATEPOINT 0, 0, 0, @func, 2, 0, 2, 0, 2, 0, 2, 1, 2, 0, 2, 0, 2, 1, 0, 0, csr_64, implicit-def $rsp, implicit-def $ssp 255; CHECK-VREG: STATEPOINT 0, 0, 0, @func, 2, 0, 2, 0, 2, 0, 2, 1, 2, 0, 2, 0, 2, 1, 0, 0, csr_64, implicit-def $rsp, implicit-def $ssp 256; CHECK-VREG: %0:gr8 = MOV8ri 1 257; CHECK-VREG: $al = COPY %0 258; CHECK-VREG: RET 0, $al 259 260entry: 261 %safepoint_token = call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @func, i32 0, i32 0, i32 0, i32 0) ["gc-live" (i32 addrspace(1)* null, i32 addrspace(1)* null)] 262 %base = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token, i32 0, i32 0) 263 %derived = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token, i32 0, i32 1) 264 %safepoint_token2 = call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @func, i32 0, i32 0, i32 0, i32 0) ["gc-live" (i32 addrspace(1)* %base, i32 addrspace(1)* %derived)] 265 %base_reloc = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token2, i32 0, i32 0) 266 %derived_reloc = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token2, i32 0, i32 1) 267 %cmp1 = icmp eq i32 addrspace(1)* %base_reloc, null 268 %cmp2 = icmp eq i32 addrspace(1)* %derived_reloc, null 269 %cmp = and i1 %cmp1, %cmp2 270 ret i1 %cmp 271} 272 273; Vectors cannot go in VRegs 274; No need to check post-regalloc output as it is lowered using old scheme 275define <2 x i8 addrspace(1)*> @test_vector(<2 x i8 addrspace(1)*> %obj) gc "statepoint-example" { 276; CHECK-VREG-LABEL: name: test_vector 277; CHECK-VREG: %0:vr128 = COPY $xmm0 278; CHECK-VREG: MOVAPSmr %stack.0, 1, $noreg, 0, $noreg, %0 :: (store 16 into %stack.0) 279; CHECK-VREG: STATEPOINT 0, 0, 0, @func, 2, 0, 2, 0, 2, 0, 2, 1, 1, 16, %stack.0, 0, 2, 0, 2, 1, 0, 0, csr_64, implicit-def $rsp, implicit-def $ssp :: (volatile load store 16 on %stack.0) 280; CHECK-VREG: %1:vr128 = MOVAPSrm %stack.0, 1, $noreg, 0, $noreg :: (load 16 from %stack.0) 281; CHECK-VREG: $xmm0 = COPY %1 282; CHECK-VREG: RET 0, $xmm0 283 284entry: 285 %safepoint_token = call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @func, i32 0, i32 0, i32 0, i32 0) ["gc-live" (<2 x i8 addrspace(1)*> %obj)] 286 %obj.relocated = call coldcc <2 x i8 addrspace(1)*> @llvm.experimental.gc.relocate.v2p1i8(token %safepoint_token, i32 0, i32 0) ; (%obj, %obj) 287 ret <2 x i8 addrspace(1)*> %obj.relocated 288} 289 290 291; test limit on amount of vregs 292define void @test_limit(i32 addrspace(1)* %a, i32 addrspace(1)* %b, i32 addrspace(1)* %c, i32 addrspace(1)* %d, i32 addrspace(1)* %e) gc "statepoint-example" { 293; CHECK-VREG-LABEL: name: test_limit 294; CHECK-VREG: %4:gr64 = COPY $r8 295; CHECK-VREG: %3:gr64 = COPY $rcx 296; CHECK-VREG: %2:gr64 = COPY $rdx 297; CHECK-VREG: %1:gr64 = COPY $rsi 298; CHECK-VREG: %0:gr64 = COPY $rdi 299; CHECK-VREG: MOV64mr %stack.0, 1, $noreg, 0, $noreg, %0 :: (store 8 into %stack.0) 300; CHECK-VREG: %5:gr64, %6:gr64, %7:gr64, %8:gr64 = STATEPOINT 0, 0, 0, @func, 2, 0, 2, 0, 2, 0, 2, 5, %4(tied-def 0), %3(tied-def 1), %2(tied-def 2), %1(tied-def 3), 1, 8, %stack.0, 0, 2, 0, 2, 5, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, csr_64, implicit-def $rsp, implicit-def $ssp :: (volatile load store 8 on %stack.0) 301; CHECK-VREG: %9:gr64 = MOV64rm %stack.0, 1, $noreg, 0, $noreg :: (load 8 from %stack.0) 302; CHECK-VREG: $rdi = COPY %9 303; CHECK-VREG: $rsi = COPY %8 304; CHECK-VREG: $rdx = COPY %7 305; CHECK-VREG: $rcx = COPY %6 306; CHECK-VREG: $r8 = COPY %5 307; CHECK-VREG: CALL64pcrel32 @consume5, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit $rsi, implicit $rdx, implicit $rcx, implicit $r8, implicit-def $rsp, implicit-def $ssp 308; CHECK-VREG: RET 0 309entry: 310 %safepoint_token = tail call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @func, i32 0, i32 0, i32 0, i32 0) ["gc-live" (i32 addrspace(1)* %a, i32 addrspace(1)* %b, i32 addrspace(1)* %c, i32 addrspace(1)* %d, i32 addrspace(1)* %e)] 311 %rel1 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token, i32 0, i32 0) 312 %rel2 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token, i32 1, i32 1) 313 %rel3 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token, i32 2, i32 2) 314 %rel4 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token, i32 3, i32 3) 315 %rel5 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token, i32 4, i32 4) 316 call void @consume5(i32 addrspace(1)* %rel1, i32 addrspace(1)* %rel2, i32 addrspace(1)* %rel3, i32 addrspace(1)* %rel4, i32 addrspace(1)* %rel5) 317 ret void 318} 319 320; Different IR Values which maps to the same SDValue must be assigned to the same VReg. 321; This is test is similar to test_gcptr_uniqueing but explicitly uses invokes for which this is important 322; Otherwise we may get a copy of statepoint result, inserted at the end ot statepoint block and used at landing pad 323define void @test_duplicate_ir_values() gc "statepoint-example" personality i32* ()* @fake_personality_function{ 324;CHECK-VREG-LABEL: name: test_duplicate_ir_values 325;CHECK-VREG: bb.0.entry: 326;CHECK-VREG: %0:gr64 = STATEPOINT 1, 16, 5, %8, $edi, $rsi, $edx, $ecx, $r8d, 2, 0, 2, 0, 2, 0, 2, 1, killed %1(tied-def 0), 2, 0, 2, 1, 0, 0, csr_64, implicit-def $rsp, implicit-def $ssp, implicit-def $eax 327;CHECK-VREG: JMP_1 %bb.1 328;CHECK-VREG: bb.1.normal_continue: 329;CHECK-VREG: MOV64mr %stack.0, 1, $noreg, 0, $noreg, %0 :: (store 8 into %stack.0) 330;CHECK-VREG: %13:gr32 = MOV32ri 10 331;CHECK-VREG: $edi = COPY %13 332;CHECK-VREG: STATEPOINT 2882400000, 0, 1, @__llvm_deoptimize, $edi, 2, 0, 2, 2, 2, 2, 1, 8, %stack.0, 0, 1, 8, %stack.0, 0, 2, 0, 2, 0, 2, 0, csr_64, implicit-def $rsp, implicit-def $ssp :: (volatile load store 8 on %stack.0) 333;CHECK-VREG: bb.2.exceptional_return (landing-pad): 334;CHECK-VREG: EH_LABEL <mcsymbol > 335;CHECK-VREG: MOV64mr %stack.0, 1, $noreg, 0, $noreg, %0 :: (store 8 into %stack.0) 336;CHECK-VREG: %12:gr32 = MOV32ri -271 337;CHECK-VREG: $edi = COPY %12 338;CHECK-VREG: STATEPOINT 2882400000, 0, 1, @__llvm_deoptimize, $edi, 2, 0, 2, 0, 2, 1, 1, 8, %stack.0, 0, 2, 0, 2, 0, 2, 0, csr_64, implicit-def $rsp, implicit-def $ssp :: (volatile load store 8 on %stack.0) 339 340entry: 341 %local.0 = load i8 addrspace(1)*, i8 addrspace(1)* addrspace(1)* undef, align 8 342 %local.9 = load i8 addrspace(1)*, i8 addrspace(1)* addrspace(1)* undef, align 8 343 %statepoint_token1 = invoke token (i64, i32, i32 (i32, i8 addrspace(1)*, i32, i32, i32)*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_i32i32p1i8i32i32i32f(i64 1, i32 16, i32 (i32, i8 addrspace(1)*, i32, i32, i32)* nonnull @foo, i32 5, i32 0, i32 undef, i8 addrspace(1)* undef, i32 undef, i32 undef, i32 undef, i32 0, i32 0) [ "deopt"(), "gc-live"(i8 addrspace(1)* %local.0, i8 addrspace(1)* %local.9) ] 344 to label %normal_continue unwind label %exceptional_return 345 346normal_continue: ; preds = %entry 347 %local.0.relocated1 = call coldcc i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(token %statepoint_token1, i32 0, i32 0) ; (%local.0, %local.0) 348 %local.9.relocated1 = call coldcc i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(token %statepoint_token1, i32 1, i32 1) ; (%local.9, %local.9) 349 %safepoint_token2 = call token (i64, i32, void (i32)*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidi32f(i64 2882400000, i32 0, void (i32)* nonnull @__llvm_deoptimize, i32 1, i32 2, i32 10, i32 0, i32 0) [ "deopt"(i8 addrspace(1)* %local.0.relocated1, i8 addrspace(1)* %local.9.relocated1), "gc-live"() ] 350 unreachable 351 352exceptional_return: ; preds = %entry 353 %lpad_token11090 = landingpad token 354 cleanup 355 %local.9.relocated2 = call coldcc i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(token %lpad_token11090, i32 1, i32 1) ; (%local.9, %local.9) 356 %safepoint_token3 = call token (i64, i32, void (i32)*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidi32f(i64 2882400000, i32 0, void (i32)* nonnull @__llvm_deoptimize, i32 1, i32 0, i32 -271, i32 0, i32 0) [ "deopt"(i8 addrspace(1)* %local.9.relocated2), "gc-live"() ] 357 unreachable 358} 359 360; Test that CopyFromReg emitted during ISEL processing of gc.relocate are properly ordered w.r.t. statepoint. 361define i8 addrspace(1)* @test_isel_sched(i8 addrspace(1)* %0, i8 addrspace(1)* %1, i32 %2) gc "statepoint-example" { 362;CHECK-VREG-LABEL: name: test_isel_sched 363;CHECK-VREG: bb.0.entry: 364;CHECK-VREG: %2:gr32 = COPY $edx 365;CHECK-VREG: %1:gr64 = COPY $rsi 366;CHECK-VREG: %0:gr64 = COPY $rdi 367;CHECK-VREG: TEST32rr %2, %2, implicit-def $eflags 368;CHECK-VREG: %5:gr64 = CMOV64rr %1, %0, 4, implicit $eflags 369;CHECK-VREG: %6:gr32 = MOV32r0 implicit-def dead $eflags 370;CHECK-VREG: %7:gr64 = SUBREG_TO_REG 0, killed %6, %subreg.sub_32bit 371;CHECK-VREG: $rdi = COPY %7 372;CHECK-VREG: $rsi = COPY %5 373;CHECK-VREG: %3:gr64, %4:gr64 = STATEPOINT 10, 0, 2, @bar, $rdi, $rsi, 2, 0, 2, 0, 2, 0, 2, 2, %1(tied-def 0), %0(tied-def 1), 2, 0, 2, 2, 0, 0, 1, 1, csr_64, implicit-def $rsp, implicit-def $ssp 374;CHECK-VREG: TEST32rr %2, %2, implicit-def $eflags 375;CHECK-VREG: %8:gr64 = CMOV64rr %3, %4, 4, implicit $eflags 376;CHECK-VREG: $rax = COPY %8 377;CHECK-VREG: RET 0, $rax 378entry: 379 %cmp = icmp eq i32 %2, 0 380 %ptr = select i1 %cmp, i8 addrspace(1)* %0, i8 addrspace(1)* %1 381 %token = call token (i64, i32, void (i8 addrspace(1)*, i8 addrspace(1)*)*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidp1i8p1i8f(i64 10, i32 0, void (i8 addrspace(1)*, i8 addrspace(1)*)* @bar, i32 2, i32 0, i8 addrspace(1)* null, i8 addrspace(1)* %ptr, i32 0, i32 0) [ "deopt"(), "gc-live"(i8 addrspace(1)* %0, i8 addrspace(1)* %1) ] 382 %rel0 = call coldcc i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(token %token, i32 0, i32 0) 383 %rel1 = call coldcc i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(token %token, i32 1, i32 1) 384 %res = select i1 %cmp, i8 addrspace(1)* %rel0, i8 addrspace(1)* %rel1 385 ret i8 addrspace(1)* %res 386} 387 388declare token @llvm.experimental.gc.statepoint.p0f_i1f(i64, i32, i1 ()*, i32, i32, ...) 389declare token @llvm.experimental.gc.statepoint.p0f_isVoidf(i64, i32, void ()*, i32, i32, ...) 390declare dso_local i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token, i32, i32) 391declare dso_local i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(token, i32, i32) 392declare <2 x i8 addrspace(1)*> @llvm.experimental.gc.relocate.v2p1i8(token, i32, i32) 393declare dso_local i1 @llvm.experimental.gc.result.i1(token) 394declare dso_local void @__llvm_deoptimize(i32) 395declare token @llvm.experimental.gc.statepoint.p0f_isVoidi32f(i64 immarg, i32 immarg, void (i32)*, i32 immarg, i32 immarg, ...) 396declare token @llvm.experimental.gc.statepoint.p0f_i32i32p1i8i32i32i32f(i64 immarg, i32 immarg, i32 (i32, i8 addrspace(1)*, i32, i32, i32)*, i32 immarg, i32 immarg, ...) 397declare token @llvm.experimental.gc.statepoint.p0f_isVoidp1i8p1i8f(i64 immarg, i32 immarg, void (i8 addrspace(1)*, i8 addrspace(1)*)*, i32 immarg, i32 immarg, ...) 398 399