241 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py2; RUN: llc -verify-machineinstrs < %s | FileCheck %s3; A collection of basic functionality tests for statepoint lowering - most4; interesting cornercases are exercised through the x86 tests.5 6target datalayout = "e-i64:64-f80:128-n8:16:32:64-S128"7target triple = "aarch64-unknown-linux-gnu"8 9%struct = type { i64, i64 }10 11declare zeroext i1 @return_i1()12declare zeroext i32 @return_i32()13declare ptr @return_i32ptr()14declare float @return_float()15declare %struct @return_struct()16declare void @varargf(i32, ...)17 18define i1 @test_i1_return() gc "statepoint-example" {19; CHECK-LABEL: test_i1_return:20; CHECK: // %bb.0: // %entry21; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill22; CHECK-NEXT: .cfi_def_cfa_offset 1623; CHECK-NEXT: .cfi_offset w30, -1624; CHECK-NEXT: bl return_i125; CHECK-NEXT: .Ltmp0:26; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload27; CHECK-NEXT: ret28; This is just checking that a i1 gets lowered normally when there's no extra29; state arguments to the statepoint30entry:31 %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)32 %call1 = call zeroext i1 @llvm.experimental.gc.result.i1(token %safepoint_token)33 ret i1 %call134}35 36define i32 @test_i32_return() gc "statepoint-example" {37; CHECK-LABEL: test_i32_return:38; CHECK: // %bb.0: // %entry39; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill40; CHECK-NEXT: .cfi_def_cfa_offset 1641; CHECK-NEXT: .cfi_offset w30, -1642; CHECK-NEXT: bl return_i3243; CHECK-NEXT: .Ltmp1:44; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload45; CHECK-NEXT: ret46entry:47 %safepoint_token = tail call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 0, i32 0, ptr elementtype(i32 ()) @return_i32, i32 0, i32 0, i32 0, i32 0)48 %call1 = call zeroext i32 @llvm.experimental.gc.result.i32(token %safepoint_token)49 ret i32 %call150}51 52define ptr @test_i32ptr_return() gc "statepoint-example" {53; CHECK-LABEL: test_i32ptr_return:54; CHECK: // %bb.0: // %entry55; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill56; CHECK-NEXT: .cfi_def_cfa_offset 1657; CHECK-NEXT: .cfi_offset w30, -1658; CHECK-NEXT: bl return_i32ptr59; CHECK-NEXT: .Ltmp2:60; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload61; CHECK-NEXT: ret62entry:63 %safepoint_token = tail call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 0, i32 0, ptr elementtype(ptr ()) @return_i32ptr, i32 0, i32 0, i32 0, i32 0)64 %call1 = call ptr @llvm.experimental.gc.result.p0(token %safepoint_token)65 ret ptr %call166}67 68define float @test_float_return() gc "statepoint-example" {69; CHECK-LABEL: test_float_return:70; CHECK: // %bb.0: // %entry71; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill72; CHECK-NEXT: .cfi_def_cfa_offset 1673; CHECK-NEXT: .cfi_offset w30, -1674; CHECK-NEXT: bl return_float75; CHECK-NEXT: .Ltmp3:76; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload77; CHECK-NEXT: ret78entry:79 %safepoint_token = tail call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 0, i32 0, ptr elementtype(float ()) @return_float, i32 0, i32 0, i32 0, i32 0)80 %call1 = call float @llvm.experimental.gc.result.f32(token %safepoint_token)81 ret float %call182}83 84define %struct @test_struct_return() gc "statepoint-example" {85; CHECK-LABEL: test_struct_return:86; CHECK: // %bb.0: // %entry87; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill88; CHECK-NEXT: .cfi_def_cfa_offset 1689; CHECK-NEXT: .cfi_offset w30, -1690; CHECK-NEXT: bl return_struct91; CHECK-NEXT: .Ltmp4:92; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload93; CHECK-NEXT: ret94entry:95 %safepoint_token = tail call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 0, i32 0, ptr elementtype(%struct ()) @return_struct, i32 0, i32 0, i32 0, i32 0)96 %call1 = call %struct @llvm.experimental.gc.result.struct(token %safepoint_token)97 ret %struct %call198}99 100define i1 @test_relocate(ptr addrspace(1) %a) gc "statepoint-example" {101; CHECK-LABEL: test_relocate:102; CHECK: // %bb.0: // %entry103; CHECK-NEXT: stp x30, x0, [sp, #-16]! // 8-byte Folded Spill104; CHECK-NEXT: .cfi_def_cfa_offset 16105; CHECK-NEXT: .cfi_offset w30, -16106; CHECK-NEXT: bl return_i1107; CHECK-NEXT: .Ltmp5:108; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload109; CHECK-NEXT: ret110; Check that an ununsed relocate has no code-generation impact111entry:112 %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)]113 %call1 = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %safepoint_token, i32 0, i32 0)114 %call2 = call zeroext i1 @llvm.experimental.gc.result.i1(token %safepoint_token)115 ret i1 %call2116}117 118define void @test_void_vararg() gc "statepoint-example" {119; CHECK-LABEL: test_void_vararg:120; CHECK: // %bb.0: // %entry121; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill122; CHECK-NEXT: .cfi_def_cfa_offset 16123; CHECK-NEXT: .cfi_offset w30, -16124; CHECK-NEXT: mov w0, #42 // =0x2a125; CHECK-NEXT: mov w1, #43 // =0x2b126; CHECK-NEXT: bl varargf127; CHECK-NEXT: .Ltmp6:128; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload129; CHECK-NEXT: ret130; Check a statepoint wrapping a *ptr returning vararg function works131entry:132 %safepoint_token = tail call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 0, i32 0, ptr elementtype(void (i32, ...)) @varargf, i32 2, i32 0, i32 42, i32 43, i32 0, i32 0)133 ;; if we try to use the result from a statepoint wrapping a134 ;; non-void-returning varargf, we will experience a crash.135 ret void136}137 138define i1 @test_i1_return_patchable() gc "statepoint-example" {139; CHECK-LABEL: test_i1_return_patchable:140; CHECK: // %bb.0: // %entry141; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill142; CHECK-NEXT: .cfi_def_cfa_offset 16143; CHECK-NEXT: .cfi_offset w30, -16144; CHECK-NEXT: nop145; CHECK-NEXT: .Ltmp7:146; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload147; CHECK-NEXT: ret148; A patchable variant of test_i1_return149entry:150 %safepoint_token = tail call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 0, i32 4, ptr elementtype(i1 ()) null, i32 0, i32 0, i32 0, i32 0)151 %call1 = call zeroext i1 @llvm.experimental.gc.result.i1(token %safepoint_token)152 ret i1 %call1153}154 155declare void @consume(ptr addrspace(1) %obj)156 157define i1 @test_cross_bb(ptr addrspace(1) %a, i1 %external_cond) gc "statepoint-example" {158; CHECK-LABEL: test_cross_bb:159; CHECK: // %bb.0: // %entry160; CHECK-NEXT: str x30, [sp, #-32]! // 8-byte Folded Spill161; CHECK-NEXT: stp x20, x19, [sp, #16] // 16-byte Folded Spill162; CHECK-NEXT: .cfi_def_cfa_offset 32163; CHECK-NEXT: .cfi_offset w19, -8164; CHECK-NEXT: .cfi_offset w20, -16165; CHECK-NEXT: .cfi_offset w30, -32166; CHECK-NEXT: mov w20, w1167; CHECK-NEXT: str x0, [sp, #8]168; CHECK-NEXT: bl return_i1169; CHECK-NEXT: .Ltmp8:170; CHECK-NEXT: tbz w20, #0, .LBB8_2171; CHECK-NEXT: // %bb.1: // %left172; CHECK-NEXT: mov w19, w0173; CHECK-NEXT: ldr x0, [sp, #8]174; CHECK-NEXT: bl consume175; CHECK-NEXT: b .LBB8_3176; CHECK-NEXT: .LBB8_2:177; CHECK-NEXT: mov w19, #1 // =0x1178; CHECK-NEXT: .LBB8_3: // %common.ret179; CHECK-NEXT: and w0, w19, #0x1180; CHECK-NEXT: ldp x20, x19, [sp, #16] // 16-byte Folded Reload181; CHECK-NEXT: ldr x30, [sp], #32 // 8-byte Folded Reload182; CHECK-NEXT: ret183entry:184 %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)]185 br i1 %external_cond, label %left, label %right186 187left:188 %call1 = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %safepoint_token, i32 0, i32 0)189 %call2 = call zeroext i1 @llvm.experimental.gc.result.i1(token %safepoint_token)190 call void @consume(ptr addrspace(1) %call1)191 ret i1 %call2192 193right:194 ret i1 true195}196 197%struct2 = type { i64, i64, i64 }198 199declare void @consume_attributes(i32, ptr nest, i32, ptr byval(%struct2))200 201define void @test_attributes(ptr byval(%struct2) %s) gc "statepoint-example" {202; CHECK-LABEL: test_attributes:203; CHECK: // %bb.0: // %entry204; CHECK-NEXT: sub sp, sp, #48205; CHECK-NEXT: str x30, [sp, #32] // 8-byte Spill206; CHECK-NEXT: .cfi_def_cfa_offset 48207; CHECK-NEXT: .cfi_offset w30, -16208; CHECK-NEXT: ldr x8, [sp, #64]209; CHECK-NEXT: ldr q0, [sp, #48]210; CHECK-NEXT: mov x15, xzr211; CHECK-NEXT: mov w0, #42 // =0x2a212; CHECK-NEXT: mov w1, #17 // =0x11213; CHECK-NEXT: str x8, [sp, #16]214; CHECK-NEXT: str q0, [sp]215; CHECK-NEXT: bl consume_attributes216; CHECK-NEXT: .Ltmp9:217; CHECK-NEXT: ldr x30, [sp, #32] // 8-byte Reload218; CHECK-NEXT: add sp, sp, #48219; CHECK-NEXT: ret220entry:221; Check that arguments with attributes are lowered correctly.222; We call a function that has a nest argument and a byval argument.223 %statepoint_token = call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 0, i32 0, ptr elementtype(void (i32, ptr, i32, ptr)) @consume_attributes, i32 4, i32 0, i32 42, ptr nest null, i32 17, ptr byval(%struct2) %s, i32 0, i32 0)224 ret void225}226 227declare token @llvm.experimental.gc.statepoint.p0(i64, i32, ptr, i32, i32, ...)228declare i1 @llvm.experimental.gc.result.i1(token)229 230declare i32 @llvm.experimental.gc.result.i32(token)231 232declare ptr @llvm.experimental.gc.result.p0(token)233 234declare float @llvm.experimental.gc.result.f32(token)235 236declare %struct @llvm.experimental.gc.result.struct(token)237 238 239 240declare ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token, i32, i32)241