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(ptr addrspace(1)) 16declare dso_local void @consume2(ptr addrspace(1), ptr addrspace(1)) 17declare dso_local void @consume5(ptr addrspace(1), ptr addrspace(1), ptr addrspace(1), ptr addrspace(1), ptr addrspace(1)) 18declare dso_local void @use1(ptr addrspace(1), ptr addrspace(1)) 19declare dso_local void @bar(ptr addrspace(1), ptr addrspace(1)) 20declare ptr addrspace(1) @dummy(i32) 21 22; test most simple relocate 23define i1 @test_relocate(ptr addrspace(1) %a) gc "statepoint-example" { 24; CHECK-VREG-LABEL: name: test_relocate 25; CHECK-VREG: %0:gr64 = COPY $rdi 26; 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 27; CHECK-VREG: %2:gr8 = COPY $al 28; CHECK-VREG: $rdi = COPY %1 29; CHECK-VREG: CALL64pcrel32 @consume, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp 30 31; CHECK-PREG-LABEL: name: test_relocate 32; CHECK-PREG: renamable $rbx = COPY $rdi 33; 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 34; CHECK-PREG: renamable $bpl = COPY $al 35; CHECK-PREG: $rdi = COPY killed renamable $rbx 36; CHECK-PREG: CALL64pcrel32 @consume, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp 37 38entry: 39 %safepoint_token = tail call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 0, i32 0, ptr elementtype(i1 ()) @return_i1, i32 0, i32 0, i32 0, i32 0) ["gc-live" (ptr addrspace(1) %a)] 40 %rel1 = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %safepoint_token, i32 0, i32 0) 41 %res1 = call zeroext i1 @llvm.experimental.gc.result.i1(token %safepoint_token) 42 call void @consume(ptr addrspace(1) %rel1) 43 ret i1 %res1 44} 45; test pointer variables intermixed with pointer constants 46define void @test_mixed(ptr addrspace(1) %a, ptr addrspace(1) %b, ptr addrspace(1) %c) gc "statepoint-example" { 47; CHECK-VREG-LABEL: name: test_mixed 48; CHECK-VREG: %2:gr64 = COPY $rdx 49; CHECK-VREG: %1:gr64 = COPY $rsi 50; CHECK-VREG: %0:gr64 = COPY $rdi 51; 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 52; CHECK-VREG: %6:gr32 = MOV32r0 implicit-def dead $eflags 53; CHECK-VREG: %7:gr64 = SUBREG_TO_REG 0, killed %6, %subreg.sub_32bit 54; CHECK-VREG: $rdi = COPY %5 55; CHECK-VREG: $rsi = COPY %7 56; CHECK-VREG: $rdx = COPY %4 57; CHECK-VREG: $rcx = COPY %7 58; CHECK-VREG: $r8 = COPY %3 59; 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 60 61; CHECK-PREG-LABEL: name: test_mixed 62; CHECK-PREG: renamable $rbx = COPY $rdx 63; CHECK-PREG: renamable $r14 = COPY $rsi 64; CHECK-PREG: renamable $r15 = COPY $rdi 65; CHECK-PREG: renamable $rbx, renamable $r14, renamable $r15 = STATEPOINT 0, 0, 0, @func, 2, 0, 2, 0, 2, 0, 2, 4, killed renamable $rbx(tied-def 0), 2, 0, killed renamable $r14(tied-def 1), killed renamable $r15(tied-def 2), 2, 0, 2, 4, 0, 0, 1, 1, 2, 2, 3, 3, csr_64, implicit-def $rsp, implicit-def $ssp 66; CHECK-PREG: $rdi = COPY killed renamable $r15 67; CHECK-PREG: dead $esi = MOV32r0 implicit-def dead $eflags, implicit-def $rsi 68; CHECK-PREG: $rdx = COPY killed renamable $r14 69; CHECK-PREG: dead $ecx = MOV32r0 implicit-def dead $eflags, implicit-def $rcx 70; CHECK-PREG: $r8 = COPY killed renamable $rbx 71; 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 72 73entry: 74 %safepoint_token = tail call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 0, i32 0, ptr elementtype(void ()) @func, i32 0, i32 0, i32 0, i32 0) ["gc-live" (ptr addrspace(1) %a, ptr addrspace(1) null, ptr addrspace(1) %b, ptr addrspace(1) null, ptr addrspace(1) %c)] 75 %rel1 = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %safepoint_token, i32 0, i32 0) 76 %rel2 = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %safepoint_token, i32 1, i32 1) 77 %rel3 = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %safepoint_token, i32 2, i32 2) 78 %rel4 = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %safepoint_token, i32 3, i32 3) 79 %rel5 = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %safepoint_token, i32 4, i32 4) 80 call void @consume5(ptr addrspace(1) %rel1, ptr addrspace(1) %rel2, ptr addrspace(1) %rel3, ptr addrspace(1) %rel4, ptr addrspace(1) %rel5) 81 ret void 82} 83 84; same as above, but for alloca 85define ptr addrspace(1) @test_alloca(ptr addrspace(1) %ptr) gc "statepoint-example" { 86; CHECK-VREG-LABEL: name: test_alloca 87; CHECK-VREG: %0:gr64 = COPY $rdi 88; CHECK-VREG: MOV64mr %stack.0.alloca, 1, $noreg, 0, $noreg, %0 :: (store (s64) into %ir.alloca) 89; 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 (s64) on %stack.0.alloca) 90; CHECK-VREG: %2:gr8 = COPY $al 91; CHECK-VREG: %3:gr64 = MOV64rm %stack.0.alloca, 1, $noreg, 0, $noreg :: (dereferenceable load (s64) from %ir.alloca) 92; CHECK-VREG: $rdi = COPY %1 93; CHECK-VREG: CALL64pcrel32 @consume, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp 94 95; CHECK-PREG-LABEL: name: test_alloca 96; CHECK-PREG: renamable $rbx = COPY $rdi 97; CHECK-PREG: MOV64mr %stack.0.alloca, 1, $noreg, 0, $noreg, renamable $rbx :: (store (s64) into %ir.alloca) 98; 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 (s64) on %stack.0.alloca) 99; CHECK-PREG: renamable $r14 = MOV64rm %stack.0.alloca, 1, $noreg, 0, $noreg :: (dereferenceable load (s64) from %ir.alloca) 100; CHECK-PREG: $rdi = COPY killed renamable $rbx 101; CHECK-PREG: CALL64pcrel32 @consume, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp 102 103entry: 104 %alloca = alloca ptr addrspace(1), align 8 105 store ptr addrspace(1) %ptr, ptr %alloca 106 %safepoint_token = call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 0, i32 0, ptr elementtype(i1 ()) @return_i1, i32 0, i32 0, i32 0, i32 0) ["gc-live" (ptr %alloca, ptr addrspace(1) %ptr)] 107 %rel1 = load ptr addrspace(1), ptr %alloca 108 %rel2 = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %safepoint_token, i32 1, i32 1) 109 call void @consume(ptr addrspace(1) %rel2) 110 ret ptr addrspace(1) %rel1 111} 112 113; test base != derived 114define void @test_base_derived(ptr addrspace(1) %base, ptr addrspace(1) %derived) gc "statepoint-example" { 115; CHECK-VREG-LABEL: name: test_base_derived 116; CHECK-VREG: %1:gr64 = COPY $rsi 117; CHECK-VREG: %0:gr64 = COPY $rdi 118; 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 119; CHECK-VREG: $rdi = COPY %2 120; CHECK-VREG: CALL64pcrel32 @consume, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp 121 122; CHECK-PREG-LABEL: name: test_base_derived 123; CHECK-PREG: renamable $rbx = COPY $rsi 124; 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 125; CHECK-PREG: $rdi = COPY killed renamable $rbx 126; CHECK-PREG: CALL64pcrel32 @consume, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp 127 128 %safepoint_token = tail call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 0, i32 0, ptr elementtype(void ()) @func, i32 0, i32 0, i32 0, i32 0) ["gc-live" (ptr addrspace(1) %base, ptr addrspace(1) %derived)] 129 %reloc = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %safepoint_token, i32 0, i32 1) 130 call void @consume(ptr addrspace(1) %reloc) 131 ret void 132} 133 134; deopt GC pointer not present in GC args must be spilled 135define void @test_deopt_gcpointer(ptr addrspace(1) %a, ptr addrspace(1) %b) gc "statepoint-example" { 136; CHECK-VREG-LABEL: name: test_deopt_gcpointer 137; CHECK-VREG: %1:gr64 = COPY $rsi 138; CHECK-VREG: %0:gr64 = COPY $rdi 139; CHECK-VREG: %2:gr64, %3:gr64 = STATEPOINT 0, 0, 0, @func, 2, 0, 2, 0, 2, 1, %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 140; CHECK-VREG: $rdi = COPY %2 141; CHECK-VREG: CALL64pcrel32 @consume, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp 142; CHECK-VREG: RET 0 143 144; CHECK-PREG-LABEL: name: test_deopt_gcpointer 145; CHECK-PREG: renamable $rbx = COPY $rsi 146; CHECK-PREG: renamable $r14 = COPY $rdi 147; CHECK-PREG: renamable $rbx, dead renamable $r14 = STATEPOINT 0, 0, 0, @func, 2, 0, 2, 0, 2, 1, killed renamable $r14, 2, 2, killed renamable $rbx(tied-def 0), renamable $r14(tied-def 1), 2, 0, 2, 2, 0, 0, 1, 1, csr_64, implicit-def $rsp, implicit-def $ssp 148; CHECK-PREG: $rdi = COPY killed renamable $rbx 149; CHECK-PREG: CALL64pcrel32 @consume, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp 150 151 %safepoint_token = tail call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 0, i32 0, ptr elementtype(void ()) @func, i32 0, i32 0, i32 0, i32 0) ["deopt" (ptr addrspace(1) %a), "gc-live" (ptr addrspace(1) %b)] 152 %rel = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %safepoint_token, i32 0, i32 0) 153 call void @consume(ptr addrspace(1) %rel) 154 ret void 155} 156 157;; Two gc.relocates of the same input, should require only a single spill/fill 158define void @test_gcrelocate_uniqueing(ptr addrspace(1) %ptr) gc "statepoint-example" { 159; CHECK-VREG-LABEL: name: test_gcrelocate_uniqueing 160; CHECK-VREG: %0:gr64 = COPY $rdi 161; 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 162; CHECK-VREG: $rdi = COPY %1 163; CHECK-VREG: $rsi = COPY %1 164; CHECK-VREG: CALL64pcrel32 @consume2, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit $rsi, implicit-def $rsp, implicit-def $ssp 165 166; CHECK-PREG-LABEL: name: test_gcrelocate_uniqueing 167; CHECK-PREG: renamable $rbx = COPY $rdi 168; 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 169; CHECK-PREG: $rdi = COPY renamable $rbx 170; CHECK-PREG: $rsi = COPY killed renamable $rbx 171; CHECK-PREG: CALL64pcrel32 @consume2, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit killed $rsi, implicit-def $rsp, implicit-def $ssp 172 173 %tok = tail call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 0, i32 0, ptr elementtype(void ()) @func, i32 0, i32 0, i32 0, i32 0) ["deopt" (ptr addrspace(1) %ptr, i32 undef), "gc-live" (ptr addrspace(1) %ptr, ptr addrspace(1) %ptr)] 174 %a = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %tok, i32 0, i32 0) 175 %b = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %tok, i32 1, i32 1) 176 call void @consume2(ptr addrspace(1) %a, ptr addrspace(1) %b) 177 ret void 178} 179 180; Two gc.relocates of a bitcasted pointer should only require a single spill/fill 181define void @test_gcptr_uniqueing(ptr addrspace(1) %ptr) gc "statepoint-example" { 182; CHECK-VREG-LABEL: name: test_gcptr_uniqueing 183; CHECK-VREG: %0:gr64 = COPY $rdi 184; CHECK-VREG: ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp 185; 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 186; CHECK-VREG: ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp 187; CHECK-VREG: ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp 188; CHECK-VREG: $rdi = COPY %1 189; CHECK-VREG: $rsi = COPY %1 190; CHECK-VREG: CALL64pcrel32 @use1, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit $rsi, implicit-def $rsp, implicit-def $ssp 191 192; CHECK-PREG-LABEL: name: test_gcptr_uniqueing 193; CHECK-PREG: renamable $rbx = COPY $rdi 194; 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 195; CHECK-PREG: $rdi = COPY renamable $rbx 196; CHECK-PREG: $rsi = COPY killed renamable $rbx 197; CHECK-PREG: CALL64pcrel32 @use1, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit killed $rsi, implicit-def $rsp, implicit-def $ssp 198 199 %tok = tail call token (i64, i32, ptr, i32, i32, ...) 200 @llvm.experimental.gc.statepoint.p0(i64 0, i32 0, ptr elementtype(void ()) @func, i32 0, i32 0, i32 0, i32 0) ["deopt" (ptr addrspace(1) %ptr, i32 undef), "gc-live" (ptr addrspace(1) %ptr, ptr addrspace(1) %ptr)] 201 %a = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %tok, i32 0, i32 0) 202 %b = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %tok, i32 1, i32 1) 203 call void @use1(ptr addrspace(1) %a, ptr addrspace(1) %b) 204 ret void 205} 206 207define i1 @test_cross_bb(ptr addrspace(1) %a, i1 %external_cond) gc "statepoint-example" { 208; CHECK-VREG-LABEL: name: test_cross_bb 209; CHECK-VREG: bb.0.entry: 210; CHECK-VREG: %1:gr32 = COPY $esi 211; CHECK-VREG-NEXT: %0:gr64 = COPY $rdi 212; CHECK-VREG-NEXT: %4:gr8 = COPY %1.sub_8bit 213; CHECK-VREG-NEXT: ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp 214; 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 215; CHECK-VREG-NEXT: ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp 216; CHECK-VREG-NEXT: %5:gr8 = COPY $al 217; CHECK-VREG-NEXT: %3:gr8 = COPY %5 218; CHECK-VREG-NEXT: TEST8ri killed %4, 1, implicit-def $eflags 219; CHECK-VREG-NEXT: JCC_1 %bb.2, 4, implicit $eflags 220; CHECK-VREG-NEXT: JMP_1 %bb.1 221; CHECK-VREG: bb.1.left: 222; CHECK-VREG-NEXT: ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp 223; CHECK-VREG-NEXT: $rdi = COPY %2 224; CHECK-VREG-NEXT: CALL64pcrel32 @consume, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp 225; CHECK-VREG-NEXT: ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp 226; CHECK-VREG-NEXT: $al = COPY %3 227; CHECK-VREG-NEXT: RET 0, $al 228; CHECK-VREG: bb.2.right: 229; CHECK-VREG-NEXT: %6:gr8 = MOV8ri 1 230; CHECK-VREG-NEXT: $al = COPY %6 231; CHECK-VREG-NEXT: RET 0, $al 232 233entry: 234 %safepoint_token = tail call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 0, i32 0, ptr elementtype(i1 ()) @return_i1, i32 0, i32 0, i32 0, i32 0) ["gc-live" (ptr addrspace(1) %a)] 235 br i1 %external_cond, label %left, label %right 236 237left: 238 %call1 = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %safepoint_token, i32 0, i32 0) 239 %call2 = call zeroext i1 @llvm.experimental.gc.result.i1(token %safepoint_token) 240 call void @consume(ptr addrspace(1) %call1) 241 ret i1 %call2 242 243right: 244 ret i1 true 245} 246 247; Local and non-local relocates of the same value 248; CHECK-VREG-LABEL: name: test_local_non_local_reloc 249; CHECK-VREG: bb.0.entry: 250; CHECK-VREG: %2:gr64 = COPY $rsi 251; CHECK-VREG: %1:gr32 = COPY $edi 252; CHECK-VREG: %4:gr8 = COPY %1.sub_8bit 253; CHECK-VREG: ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp 254; CHECK-VREG: %5:gr32 = MOV32r0 implicit-def dead $eflags 255; CHECK-VREG: $edi = COPY %5 256; CHECK-VREG: %6:gr64 = IMPLICIT_DEF 257; CHECK-VREG: %0:gr64 = STATEPOINT 2, 5, 1, killed %6, $edi, 2, 0, 2, 0, 2, 0, 2, 1, %2(tied-def 0), 2, 0, 2, 1, 0, 0, csr_64, implicit-def $rsp, implicit-def $ssp, implicit-def $rax 258; CHECK-VREG: ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp 259; CHECK-VREG: %7:gr64 = COPY $rax 260; CHECK-VREG: %3:gr64 = COPY %0 261; CHECK-VREG: TEST8ri killed %4, 1, implicit-def $eflags 262; CHECK-VREG: JCC_1 %bb.2, 5, implicit $eflags 263; CHECK-VREG: JMP_1 %bb.1 264; CHECK-VREG: bb.1.left: 265; CHECK-VREG: $rax = COPY %3 266; CHECK-VREG: RET 0, $rax 267; CHECK-VREG: bb.2.right: 268; CHECK-VREG: $rax = COPY %0 269; CHECK-VREG: RET 0, $rax 270define ptr addrspace(1) @test_local_non_local_reloc(i1 %c, ptr addrspace(1) %p) gc "statepoint-example" { 271entry: 272 %statepoint = call token (i64, i32, ptr addrspace(1) (i32)*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 2, i32 5, ptr addrspace(1) (i32)* nonnull elementtype(ptr addrspace(1) (i32)) @dummy, i32 1, i32 0, i32 0, i32 0, i32 0) [ "deopt"(), "gc-live"(ptr addrspace(1) %p) ] 273 %p.relocated = call coldcc ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %statepoint, i32 0, i32 0) ; (%p, %p) 274 br i1 %c, label %right, label %left 275 276left: 277 %p.relocated.2 = call coldcc ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %statepoint, i32 0, i32 0) ; (%p, %p) 278 ret ptr addrspace(1) %p.relocated.2 279 280right: 281 ret ptr addrspace(1) %p.relocated 282} 283 284; No need to check post-regalloc output as it is the same 285define i1 @duplicate_reloc() gc "statepoint-example" { 286; CHECK-VREG-LABEL: name: duplicate_reloc 287; CHECK-VREG: bb.0.entry: 288; 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 289; 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 290; CHECK-VREG: %0:gr8 = MOV8ri 1 291; CHECK-VREG: $al = COPY %0 292; CHECK-VREG: RET 0, $al 293 294entry: 295 %safepoint_token = call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 0, i32 0, ptr elementtype(void ()) @func, i32 0, i32 0, i32 0, i32 0) ["gc-live" (ptr addrspace(1) null, ptr addrspace(1) null)] 296 %base = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %safepoint_token, i32 0, i32 0) 297 %derived = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %safepoint_token, i32 0, i32 1) 298 %safepoint_token2 = call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 0, i32 0, ptr elementtype(void ()) @func, i32 0, i32 0, i32 0, i32 0) ["gc-live" (ptr addrspace(1) %base, ptr addrspace(1) %derived)] 299 %base_reloc = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %safepoint_token2, i32 0, i32 0) 300 %derived_reloc = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %safepoint_token2, i32 0, i32 1) 301 %cmp1 = icmp eq ptr addrspace(1) %base_reloc, null 302 %cmp2 = icmp eq ptr addrspace(1) %derived_reloc, null 303 %cmp = and i1 %cmp1, %cmp2 304 ret i1 %cmp 305} 306 307; Vectors cannot go in VRegs 308; No need to check post-regalloc output as it is lowered using old scheme 309define <2 x ptr addrspace(1)> @test_vector(<2 x ptr addrspace(1)> %obj) gc "statepoint-example" { 310; CHECK-VREG-LABEL: name: test_vector 311; CHECK-VREG: %0:vr128 = COPY $xmm0 312; CHECK-VREG: MOVAPSmr %stack.0, 1, $noreg, 0, $noreg, %0 :: (store (s128) into %stack.0) 313; 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 (s128) on %stack.0) 314; CHECK-VREG: %1:vr128 = MOVAPSrm %stack.0, 1, $noreg, 0, $noreg :: (load (s128) from %stack.0) 315; CHECK-VREG: $xmm0 = COPY %1 316; CHECK-VREG: RET 0, $xmm0 317 318entry: 319 %safepoint_token = call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 0, i32 0, ptr elementtype(void ()) @func, i32 0, i32 0, i32 0, i32 0) ["gc-live" (<2 x ptr addrspace(1)> %obj)] 320 %obj.relocated = call coldcc <2 x ptr addrspace(1)> @llvm.experimental.gc.relocate.v2p1(token %safepoint_token, i32 0, i32 0) ; (%obj, %obj) 321 ret <2 x ptr addrspace(1)> %obj.relocated 322} 323 324 325; test limit on amount of vregs 326define void @test_limit(ptr addrspace(1) %a, ptr addrspace(1) %b, ptr addrspace(1) %c, ptr addrspace(1) %d, ptr addrspace(1) %e) gc "statepoint-example" { 327; CHECK-VREG-LABEL: name: test_limit 328; CHECK-VREG: %4:gr64 = COPY $r8 329; CHECK-VREG: %3:gr64 = COPY $rcx 330; CHECK-VREG: %2:gr64 = COPY $rdx 331; CHECK-VREG: %1:gr64 = COPY $rsi 332; CHECK-VREG: %0:gr64 = COPY $rdi 333; CHECK-VREG: MOV64mr %stack.0, 1, $noreg, 0, $noreg, %0 :: (store (s64) into %stack.0) 334; 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 (s64) on %stack.0) 335; CHECK-VREG: %9:gr64 = MOV64rm %stack.0, 1, $noreg, 0, $noreg :: (load (s64) from %stack.0) 336; CHECK-VREG: $rdi = COPY %9 337; CHECK-VREG: $rsi = COPY %8 338; CHECK-VREG: $rdx = COPY %7 339; CHECK-VREG: $rcx = COPY %6 340; CHECK-VREG: $r8 = COPY %5 341; 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 342; CHECK-VREG: RET 0 343entry: 344 %safepoint_token = tail call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 0, i32 0, ptr elementtype(void ()) @func, i32 0, i32 0, i32 0, i32 0) ["gc-live" (ptr addrspace(1) %a, ptr addrspace(1) %b, ptr addrspace(1) %c, ptr addrspace(1) %d, ptr addrspace(1) %e)] 345 %rel1 = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %safepoint_token, i32 0, i32 0) 346 %rel2 = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %safepoint_token, i32 1, i32 1) 347 %rel3 = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %safepoint_token, i32 2, i32 2) 348 %rel4 = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %safepoint_token, i32 3, i32 3) 349 %rel5 = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %safepoint_token, i32 4, i32 4) 350 call void @consume5(ptr addrspace(1) %rel1, ptr addrspace(1) %rel2, ptr addrspace(1) %rel3, ptr addrspace(1) %rel4, ptr addrspace(1) %rel5) 351 ret void 352} 353 354; Test that CopyFromReg emitted during ISEL processing of gc.relocate are properly ordered w.r.t. statepoint. 355define ptr addrspace(1) @test_isel_sched(ptr addrspace(1) %0, ptr addrspace(1) %1, i32 %2) gc "statepoint-example" { 356;CHECK-VREG-LABEL: name: test_isel_sched 357;CHECK-VREG: bb.0.entry: 358;CHECK-VREG: %2:gr32 = COPY $edx 359;CHECK-VREG: %1:gr64 = COPY $rsi 360;CHECK-VREG: %0:gr64 = COPY $rdi 361;CHECK-VREG: TEST32rr %2, %2, implicit-def $eflags 362;CHECK-VREG: %3:gr64 = CMOV64rr %1, %0, 4, implicit $eflags 363;CHECK-VREG: %4:gr32 = MOV32r0 implicit-def dead $eflags 364;CHECK-VREG: %5:gr64 = SUBREG_TO_REG 0, killed %4, %subreg.sub_32bit 365;CHECK-VREG: $rdi = COPY %5 366;CHECK-VREG: $rsi = COPY %3 367;CHECK-VREG: %6:gr64, %7: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 368;CHECK-VREG: TEST32rr %2, %2, implicit-def $eflags 369;CHECK-VREG: %8:gr64 = CMOV64rr %6, killed %7, 4, implicit $eflags 370;CHECK-VREG: $rax = COPY %8 371;CHECK-VREG: RET 0, $rax 372entry: 373 %cmp = icmp eq i32 %2, 0 374 %ptr = select i1 %cmp, ptr addrspace(1) %0, ptr addrspace(1) %1 375 %token = call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 10, i32 0, ptr elementtype(void (ptr addrspace(1), ptr addrspace(1))) @bar, i32 2, i32 0, ptr addrspace(1) null, ptr addrspace(1) %ptr, i32 0, i32 0) [ "deopt"(), "gc-live"(ptr addrspace(1) %0, ptr addrspace(1) %1) ] 376 %rel0 = call coldcc ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %token, i32 0, i32 0) 377 %rel1 = call coldcc ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %token, i32 1, i32 1) 378 %res = select i1 %cmp, ptr addrspace(1) %rel0, ptr addrspace(1) %rel1 379 ret ptr addrspace(1) %res 380} 381 382; Check that ISEL of gc.relocate used in other BB does not generate extra COPY instruction. 383define i1 @test_cross_bb_reloc(ptr addrspace(1) %a, i1 %external_cond) gc "statepoint-example" { 384; CHECK-VREG-LABEL: test_cross_bb_reloc 385; CHECK-VREG: bb.0.entry: 386; CHECK-VREG: [[VREG:%[^ ]+]]:gr64 = STATEPOINT 0, 0, 0, @return_i1, 2, 0, 2, 0, 2, 0, 2, 1, %2(tied-def 0), 2, 0, 2, 1, 0, 0, csr_64, implicit-def $rsp, implicit-def $ssp, implicit-def $al 387; CHECK-VREG-NOT: COPY [[VREG]] 388; CHECK-VREG: bb.1.left: 389; CHECK-VREG: $rdi = COPY [[VREG]] 390; CHECK-VREG: CALL64pcrel32 @consume, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp 391; CHECK-VREG: $al = COPY %1 392; CHECK-VREG: RET 0, $al 393 394entry: 395 %safepoint_token = tail call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 0, i32 0, ptr elementtype(i1 ()) @return_i1, i32 0, i32 0, i32 0, i32 0) ["gc-live" (ptr addrspace(1) %a)] 396 %call1 = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %safepoint_token, i32 0, i32 0) 397 %call2 = call zeroext i1 @llvm.experimental.gc.result.i1(token %safepoint_token) 398 br i1 %external_cond, label %left, label %right 399 400left: 401 call void @consume(ptr addrspace(1) %call1) 402 ret i1 %call2 403 404right: 405 ret i1 true 406} 407 408declare token @llvm.experimental.gc.statepoint.p0(i64, i32, ptr, i32, i32, ...) 409declare dso_local ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token, i32, i32) 410declare <2 x ptr addrspace(1)> @llvm.experimental.gc.relocate.v2p1(token, i32, i32) 411declare dso_local i1 @llvm.experimental.gc.result.i1(token) 412 413