309 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py2; RUN: llc -verify-machineinstrs < %s | FileCheck %s3; This file contains a collection of basic tests to ensure we didn't4; screw up normal call lowering when there are no deopt or gc arguments.5 6target datalayout = "e-i64:64-f80:128-n8:16:32:64-S128"7target triple = "x86_64-pc-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: pushq %rax22; CHECK-NEXT: .cfi_def_cfa_offset 1623; CHECK-NEXT: callq return_i1@PLT24; CHECK-NEXT: .Ltmp0:25; CHECK-NEXT: popq %rcx26; CHECK-NEXT: .cfi_def_cfa_offset 827; CHECK-NEXT: retq28; 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: pushq %rax40; CHECK-NEXT: .cfi_def_cfa_offset 1641; CHECK-NEXT: callq return_i32@PLT42; CHECK-NEXT: .Ltmp1:43; CHECK-NEXT: popq %rcx44; CHECK-NEXT: .cfi_def_cfa_offset 845; CHECK-NEXT: retq46entry: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: pushq %rax56; CHECK-NEXT: .cfi_def_cfa_offset 1657; CHECK-NEXT: callq return_i32ptr@PLT58; CHECK-NEXT: .Ltmp2:59; CHECK-NEXT: popq %rcx60; CHECK-NEXT: .cfi_def_cfa_offset 861; CHECK-NEXT: retq62entry: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: pushq %rax72; CHECK-NEXT: .cfi_def_cfa_offset 1673; CHECK-NEXT: callq return_float@PLT74; CHECK-NEXT: .Ltmp3:75; CHECK-NEXT: popq %rax76; CHECK-NEXT: .cfi_def_cfa_offset 877; CHECK-NEXT: retq78entry: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: pushq %rax88; CHECK-NEXT: .cfi_def_cfa_offset 1689; CHECK-NEXT: callq return_struct@PLT90; CHECK-NEXT: .Ltmp4:91; CHECK-NEXT: popq %rcx92; CHECK-NEXT: .cfi_def_cfa_offset 893; CHECK-NEXT: retq94entry: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: pushq %rax104; CHECK-NEXT: .cfi_def_cfa_offset 16105; CHECK-NEXT: movq %rdi, (%rsp)106; CHECK-NEXT: callq return_i1@PLT107; CHECK-NEXT: .Ltmp5:108; CHECK-NEXT: popq %rcx109; CHECK-NEXT: .cfi_def_cfa_offset 8110; CHECK-NEXT: retq111; Check that an ununsed relocate has no code-generation impact112entry:113 %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)]114 %call1 = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %safepoint_token, i32 0, i32 0)115 %call2 = call zeroext i1 @llvm.experimental.gc.result.i1(token %safepoint_token)116 ret i1 %call2117}118 119define void @test_void_vararg() gc "statepoint-example" {120; CHECK-LABEL: test_void_vararg:121; CHECK: # %bb.0: # %entry122; CHECK-NEXT: pushq %rax123; CHECK-NEXT: .cfi_def_cfa_offset 16124; CHECK-NEXT: movl $42, %edi125; CHECK-NEXT: movl $43, %esi126; CHECK-NEXT: callq varargf@PLT127; CHECK-NEXT: .Ltmp6:128; CHECK-NEXT: popq %rax129; CHECK-NEXT: .cfi_def_cfa_offset 8130; CHECK-NEXT: retq131; Check a statepoint wrapping a *ptr returning vararg function works132entry:133 %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)134 ;; if we try to use the result from a statepoint wrapping a135 ;; non-void-returning varargf, we will experience a crash.136 ret void137}138 139define i1 @test_i1_return_patchable() gc "statepoint-example" {140; CHECK-LABEL: test_i1_return_patchable:141; CHECK: # %bb.0: # %entry142; CHECK-NEXT: pushq %rax143; CHECK-NEXT: .cfi_def_cfa_offset 16144; CHECK-NEXT: nopl (%rax)145; CHECK-NEXT: .Ltmp7:146; CHECK-NEXT: popq %rcx147; CHECK-NEXT: .cfi_def_cfa_offset 8148; CHECK-NEXT: retq149; A patchable variant of test_i1_return150entry:151 %safepoint_token = tail call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 0, i32 3, ptr elementtype(i1 ()) null, i32 0, i32 0, i32 0, i32 0)152 %call1 = call zeroext i1 @llvm.experimental.gc.result.i1(token %safepoint_token)153 ret i1 %call1154}155 156declare void @consume(ptr addrspace(1) %obj)157 158define i1 @test_cross_bb(ptr addrspace(1) %a, i1 %external_cond) gc "statepoint-example" {159; CHECK-LABEL: test_cross_bb:160; CHECK: # %bb.0: # %entry161; CHECK-NEXT: pushq %rbx162; CHECK-NEXT: .cfi_def_cfa_offset 16163; CHECK-NEXT: subq $16, %rsp164; CHECK-NEXT: .cfi_def_cfa_offset 32165; CHECK-NEXT: .cfi_offset %rbx, -16166; CHECK-NEXT: movl %esi, %ebx167; CHECK-NEXT: movq %rdi, {{[0-9]+}}(%rsp)168; CHECK-NEXT: callq return_i1@PLT169; CHECK-NEXT: .Ltmp8:170; CHECK-NEXT: testb $1, %bl171; CHECK-NEXT: je .LBB8_2172; CHECK-NEXT: # %bb.1: # %left173; CHECK-NEXT: movq {{[0-9]+}}(%rsp), %rdi174; CHECK-NEXT: movl %eax, %ebx175; CHECK-NEXT: callq consume@PLT176; CHECK-NEXT: movl %ebx, %eax177; CHECK-NEXT: jmp .LBB8_3178; CHECK-NEXT: .LBB8_2: # %right179; CHECK-NEXT: movb $1, %al180; CHECK-NEXT: .LBB8_3: # %right181; CHECK-NEXT: addq $16, %rsp182; CHECK-NEXT: .cfi_def_cfa_offset 16183; CHECK-NEXT: popq %rbx184; CHECK-NEXT: .cfi_def_cfa_offset 8185; CHECK-NEXT: retq186entry:187 %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)]188 br i1 %external_cond, label %left, label %right189 190left:191 %call1 = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %safepoint_token, i32 0, i32 0)192 %call2 = call zeroext i1 @llvm.experimental.gc.result.i1(token %safepoint_token)193 call void @consume(ptr addrspace(1) %call1)194 ret i1 %call2195 196right:197 ret i1 true198}199 200%struct2 = type { i64, i64, i64 }201 202declare void @consume_attributes(i32, ptr nest, i32, ptr byval(%struct2))203 204define void @test_attributes(ptr byval(%struct2) %s) gc "statepoint-example" {205; CHECK-LABEL: test_attributes:206; CHECK: # %bb.0: # %entry207; CHECK-NEXT: pushq %rax208; CHECK-NEXT: .cfi_def_cfa_offset 16209; CHECK-NEXT: subq $8, %rsp210; CHECK-NEXT: .cfi_adjust_cfa_offset 8211; CHECK-NEXT: movq {{[0-9]+}}(%rsp), %rax212; CHECK-NEXT: movq {{[0-9]+}}(%rsp), %rcx213; CHECK-NEXT: movq {{[0-9]+}}(%rsp), %rdx214; CHECK-NEXT: movl $42, %edi215; CHECK-NEXT: xorl %r10d, %r10d216; CHECK-NEXT: movl $17, %esi217; CHECK-NEXT: pushq %rax218; CHECK-NEXT: .cfi_adjust_cfa_offset 8219; CHECK-NEXT: pushq %rdx220; CHECK-NEXT: .cfi_adjust_cfa_offset 8221; CHECK-NEXT: pushq %rcx222; CHECK-NEXT: .cfi_adjust_cfa_offset 8223; CHECK-NEXT: callq consume_attributes@PLT224; CHECK-NEXT: .Ltmp9:225; CHECK-NEXT: addq $32, %rsp226; CHECK-NEXT: .cfi_adjust_cfa_offset -32227; CHECK-NEXT: popq %rax228; CHECK-NEXT: .cfi_def_cfa_offset 8229; CHECK-NEXT: retq230entry:231; Check that arguments with attributes are lowered correctly.232; We call a function that has a nest argument and a byval argument.233 %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)234 ret void235}236 237declare signext i1 @signext_return_i1()238 239; Check that the generated code takes the zeroext and signext return attributes240; on the GC result into account. The attribute in the return position allows the241; caller to assume that the callee did the extension already.242 243define i8 @test_signext_return(ptr) gc "statepoint-example" {244; CHECK-LABEL: test_signext_return:245; CHECK: # %bb.0: # %entry246; CHECK-NEXT: pushq %rax247; CHECK-NEXT: .cfi_def_cfa_offset 16248; CHECK-NEXT: callq signext_return_i1@PLT249; CHECK-NEXT: .Ltmp10:250; CHECK-NEXT: popq %rcx251; CHECK-NEXT: .cfi_def_cfa_offset 8252; CHECK-NEXT: retq253entry:254 %safepoint_token = tail call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 0, i32 0, ptr elementtype(i1 ()) @signext_return_i1, i32 0, i32 0, i32 0, i32 0)255 %call1 = call signext i1 @llvm.experimental.gc.result.i1(token %safepoint_token)256 %ext = sext i1 %call1 to i8257 ret i8 %ext258}259 260define i8 @test_zeroext_return() gc "statepoint-example" {261; CHECK-LABEL: test_zeroext_return:262; CHECK: # %bb.0: # %entry263; CHECK-NEXT: pushq %rax264; CHECK-NEXT: .cfi_def_cfa_offset 16265; CHECK-NEXT: callq return_i1@PLT266; CHECK-NEXT: .Ltmp11:267; CHECK-NEXT: popq %rcx268; CHECK-NEXT: .cfi_def_cfa_offset 8269; CHECK-NEXT: retq270entry:271 %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)272 %call1 = call zeroext i1 @llvm.experimental.gc.result.i1(token %safepoint_token)273 %ext = zext i1 %call1 to i8274 ret i8 %ext275}276 277define signext i1 @test_noext_signext_return() gc "statepoint-example" {278; CHECK-LABEL: test_noext_signext_return:279; CHECK: # %bb.0: # %entry280; CHECK-NEXT: pushq %rax281; CHECK-NEXT: .cfi_def_cfa_offset 16282; CHECK-NEXT: callq return_i1@PLT283; CHECK-NEXT: .Ltmp12:284; CHECK-NEXT: andb $1, %al285; CHECK-NEXT: negb %al286; CHECK-NEXT: popq %rcx287; CHECK-NEXT: .cfi_def_cfa_offset 8288; CHECK-NEXT: retq289entry:290 %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)291 %call1 = call i1 @llvm.experimental.gc.result.i1(token %safepoint_token)292 ret i1 %call1293}294 295declare token @llvm.experimental.gc.statepoint.p0(i64, i32, ptr, i32, i32, ...)296declare i1 @llvm.experimental.gc.result.i1(token)297 298declare i32 @llvm.experimental.gc.result.i32(token)299 300declare ptr @llvm.experimental.gc.result.p0(token)301 302declare float @llvm.experimental.gc.result.f32(token)303 304declare %struct @llvm.experimental.gc.result.struct(token)305 306 307 308declare ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token, i32, i32)309