200 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py2; RUN: llc --mtriple=loongarch64 -mattr=+d < %s | FileCheck %s3 4;; Perform tail call optimization for global address.5declare i32 @callee_tail(i32 %i)6define i32 @caller_tail(i32 %i) nounwind {7; CHECK-LABEL: caller_tail:8; CHECK: # %bb.0: # %entry9; CHECK-NEXT: pcaddu18i $t8, %call36(callee_tail)10; CHECK-NEXT: jr $t811entry:12 %r = tail call i32 @callee_tail(i32 %i)13 ret i32 %r14}15 16;; Perform tail call optimization for external symbol.17;; Bytes copied should be large enough, otherwise the memcpy call would be optimized to multiple ld/st insns.18@dest = global [2 x i8] zeroinitializer19declare void @llvm.memcpy.p0.p0.i32(ptr, ptr, i32, i1)20define void @caller_extern(ptr %src) optsize {21; CHECK-LABEL: caller_extern:22; CHECK: # %bb.0: # %entry23; CHECK-NEXT: pcalau12i $a1, %got_pc_hi20(dest)24; CHECK-NEXT: ld.d $a1, $a1, %got_pc_lo12(dest)25; CHECK-NEXT: ori $a2, $zero, 3326; CHECK-NEXT: move $a3, $a027; CHECK-NEXT: move $a0, $a128; CHECK-NEXT: move $a1, $a329; CHECK-NEXT: pcaddu18i $t8, %call36(memcpy)30; CHECK-NEXT: jr $t831entry:32 tail call void @llvm.memcpy.p0.p0.i32(ptr @dest, ptr %src, i32 33, i1 false)33 ret void34}35 36;; Perform indirect tail call optimization (for function pointer call).37declare void @callee_indirect1()38declare void @callee_indirect2()39define void @caller_indirect_tail(i32 %a) nounwind {40; CHECK-LABEL: caller_indirect_tail:41; CHECK: # %bb.0: # %entry42; CHECK-NEXT: pcalau12i $a1, %got_pc_hi20(callee_indirect2)43; CHECK-NEXT: ld.d $a1, $a1, %got_pc_lo12(callee_indirect2)44; CHECK-NEXT: pcalau12i $a2, %got_pc_hi20(callee_indirect1)45; CHECK-NEXT: ld.d $a2, $a2, %got_pc_lo12(callee_indirect1)46; CHECK-NEXT: addi.w $a0, $a0, 047; CHECK-NEXT: sltui $a0, $a0, 148; CHECK-NEXT: masknez $a1, $a1, $a049; CHECK-NEXT: maskeqz $a0, $a2, $a050; CHECK-NEXT: or $a0, $a0, $a151; CHECK-NEXT: jr $a052entry:53 %tobool = icmp eq i32 %a, 054 %callee = select i1 %tobool, ptr @callee_indirect1, ptr @callee_indirect255 tail call void %callee()56 ret void57}58 59;; Do not tail call optimize functions with varargs passed by stack.60declare i32 @callee_varargs(i32, ...)61define void @caller_varargs(i32 %a, i32 %b) nounwind {62; CHECK-LABEL: caller_varargs:63; CHECK: # %bb.0: # %entry64; CHECK-NEXT: addi.d $sp, $sp, -1665; CHECK-NEXT: st.d $ra, $sp, 8 # 8-byte Folded Spill66; CHECK-NEXT: st.d $a0, $sp, 067; CHECK-NEXT: move $a2, $a168; CHECK-NEXT: move $a3, $a069; CHECK-NEXT: move $a4, $a070; CHECK-NEXT: move $a5, $a171; CHECK-NEXT: move $a6, $a172; CHECK-NEXT: move $a7, $a073; CHECK-NEXT: pcaddu18i $ra, %call36(callee_varargs)74; CHECK-NEXT: jirl $ra, $ra, 075; CHECK-NEXT: ld.d $ra, $sp, 8 # 8-byte Folded Reload76; CHECK-NEXT: addi.d $sp, $sp, 1677; CHECK-NEXT: ret78entry:79 %call = tail call i32 (i32, ...) @callee_varargs(i32 %a, i32 %b, i32 %b, i32 %a, i32 %a, i32 %b, i32 %b, i32 %a, i32 %a)80 ret void81}82 83;; Do not tail call optimize if stack is used to pass parameters.84declare i32 @callee_args(i32 %a, i32 %b, i32 %c, i32 %dd, i32 %e, i32 %ff, i32 %g, i32 %h, i32 %i)85define i32 @caller_args(i32 %a, i32 %b, i32 %c, i32 %dd, i32 %e, i32 %ff, i32 %g, i32 %h, i32 %i) nounwind {86; CHECK-LABEL: caller_args:87; CHECK: # %bb.0: # %entry88; CHECK-NEXT: addi.d $sp, $sp, -1689; CHECK-NEXT: st.d $ra, $sp, 8 # 8-byte Folded Spill90; CHECK-NEXT: ld.d $t0, $sp, 1691; CHECK-NEXT: st.d $t0, $sp, 092; CHECK-NEXT: pcaddu18i $ra, %call36(callee_args)93; CHECK-NEXT: jirl $ra, $ra, 094; CHECK-NEXT: ld.d $ra, $sp, 8 # 8-byte Folded Reload95; CHECK-NEXT: addi.d $sp, $sp, 1696; CHECK-NEXT: ret97entry:98 %r = tail call i32 @callee_args(i32 %a, i32 %b, i32 %c, i32 %dd, i32 %e, i32 %ff, i32 %g, i32 %h, i32 %i)99 ret i32 %r100}101 102;; Do not tail call optimize if parameters need to be passed indirectly.103declare i32 @callee_indirect_args(i256 %a)104define void @caller_indirect_args() nounwind {105; CHECK-LABEL: caller_indirect_args:106; CHECK: # %bb.0: # %entry107; CHECK-NEXT: addi.d $sp, $sp, -48108; CHECK-NEXT: st.d $ra, $sp, 40 # 8-byte Folded Spill109; CHECK-NEXT: st.d $zero, $sp, 24110; CHECK-NEXT: vrepli.b $vr0, 0111; CHECK-NEXT: vst $vr0, $sp, 8112; CHECK-NEXT: ori $a1, $zero, 1113; CHECK-NEXT: addi.d $a0, $sp, 0114; CHECK-NEXT: st.d $a1, $sp, 0115; CHECK-NEXT: pcaddu18i $ra, %call36(callee_indirect_args)116; CHECK-NEXT: jirl $ra, $ra, 0117; CHECK-NEXT: ld.d $ra, $sp, 40 # 8-byte Folded Reload118; CHECK-NEXT: addi.d $sp, $sp, 48119; CHECK-NEXT: ret120entry:121 %call = tail call i32 @callee_indirect_args(i256 1)122 ret void123}124 125;; Do not tail call optimize if byval parameters need to be passed.126declare i32 @callee_byval(ptr byval(ptr) %a)127define i32 @caller_byval() nounwind {128; CHECK-LABEL: caller_byval:129; CHECK: # %bb.0: # %entry130; CHECK-NEXT: addi.d $sp, $sp, -32131; CHECK-NEXT: st.d $ra, $sp, 24 # 8-byte Folded Spill132; CHECK-NEXT: ld.d $a0, $sp, 16133; CHECK-NEXT: st.d $a0, $sp, 8134; CHECK-NEXT: addi.d $a0, $sp, 8135; CHECK-NEXT: pcaddu18i $ra, %call36(callee_byval)136; CHECK-NEXT: jirl $ra, $ra, 0137; CHECK-NEXT: ld.d $ra, $sp, 24 # 8-byte Folded Reload138; CHECK-NEXT: addi.d $sp, $sp, 32139; CHECK-NEXT: ret140entry:141 %a = alloca ptr142 %r = tail call i32 @callee_byval(ptr byval(ptr) %a)143 ret i32 %r144}145 146;; Do not tail call optimize if callee uses structret semantics.147%struct.A = type { i32 }148@a = global %struct.A zeroinitializer149 150declare void @callee_struct(ptr sret(%struct.A) %a)151define void @caller_nostruct() nounwind {152; CHECK-LABEL: caller_nostruct:153; CHECK: # %bb.0: # %entry154; CHECK-NEXT: addi.d $sp, $sp, -16155; CHECK-NEXT: st.d $ra, $sp, 8 # 8-byte Folded Spill156; CHECK-NEXT: pcalau12i $a0, %got_pc_hi20(a)157; CHECK-NEXT: ld.d $a0, $a0, %got_pc_lo12(a)158; CHECK-NEXT: pcaddu18i $ra, %call36(callee_struct)159; CHECK-NEXT: jirl $ra, $ra, 0160; CHECK-NEXT: ld.d $ra, $sp, 8 # 8-byte Folded Reload161; CHECK-NEXT: addi.d $sp, $sp, 16162; CHECK-NEXT: ret163entry:164 tail call void @callee_struct(ptr sret(%struct.A) @a)165 ret void166}167 168;; Do not tail call optimize if caller uses structret semantics.169declare void @callee_nostruct()170define void @caller_struct(ptr sret(%struct.A) %a) nounwind {171; CHECK-LABEL: caller_struct:172; CHECK: # %bb.0: # %entry173; CHECK-NEXT: addi.d $sp, $sp, -16174; CHECK-NEXT: st.d $ra, $sp, 8 # 8-byte Folded Spill175; CHECK-NEXT: pcaddu18i $ra, %call36(callee_nostruct)176; CHECK-NEXT: jirl $ra, $ra, 0177; CHECK-NEXT: ld.d $ra, $sp, 8 # 8-byte Folded Reload178; CHECK-NEXT: addi.d $sp, $sp, 16179; CHECK-NEXT: ret180entry:181 tail call void @callee_nostruct()182 ret void183}184 185;; Do not tail call optimize if disabled.186define i32 @disable_tail_calls(i32 %i) nounwind "disable-tail-calls"="true" {187; CHECK-LABEL: disable_tail_calls:188; CHECK: # %bb.0: # %entry189; CHECK-NEXT: addi.d $sp, $sp, -16190; CHECK-NEXT: st.d $ra, $sp, 8 # 8-byte Folded Spill191; CHECK-NEXT: pcaddu18i $ra, %call36(callee_tail)192; CHECK-NEXT: jirl $ra, $ra, 0193; CHECK-NEXT: ld.d $ra, $sp, 8 # 8-byte Folded Reload194; CHECK-NEXT: addi.d $sp, $sp, 16195; CHECK-NEXT: ret196entry:197 %rv = tail call i32 @callee_tail(i32 %i)198 ret i32 %rv199}200