Compiler projects using llvm
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc -mtriple=thumbv7-linux-gnueabihf %s -o - | FileCheck %s
; RUN: llc -mtriple=thumbv7-linux-gnueabi %s -o - | FileCheck -check-prefix=SOFTFLOAT %s
; RUN: llc -mtriple=thumbv7-linux-gnueabihf -disable-tail-calls %s -o - | FileCheck -check-prefix=HF-NOTAIL %s

; On hard-float targets, the register used to store a float return value
; changes if the call signature is varargs. The HF-NOTAIL lines are there to
; easily see when this happens.

declare float @callee_float()
declare i32 @callee_int()
declare float @callee_float_vararg(i32, ...)
declare i32 @callee_int_vararg(i32, ...)

define float @caller_float__callee_float() {
; CHECK-LABEL: caller_float__callee_float:
; CHECK:       @ %bb.0:
; CHECK-NEXT:    b callee_float
;
; SOFTFLOAT-LABEL: caller_float__callee_float:
; SOFTFLOAT:       @ %bb.0:
; SOFTFLOAT-NEXT:    b callee_float
;
; HF-NOTAIL-LABEL: caller_float__callee_float:
; HF-NOTAIL:       @ %bb.0:
; HF-NOTAIL-NEXT:    .save {r7, lr}
; HF-NOTAIL-NEXT:    push {r7, lr}
; HF-NOTAIL-NEXT:    bl callee_float
; HF-NOTAIL-NEXT:    pop {r7, pc}
  %r = tail call float @callee_float()
  ret float %r
}

define float @caller_float__callee_float_vararg() {
; CHECK-LABEL: caller_float__callee_float_vararg:
; CHECK:       @ %bb.0:
; CHECK-NEXT:    .save {r7, lr}
; CHECK-NEXT:    push {r7, lr}
; CHECK-NEXT:    movs r0, #0
; CHECK-NEXT:    bl callee_float_vararg
; CHECK-NEXT:    vmov s0, r0
; CHECK-NEXT:    pop {r7, pc}
;
; SOFTFLOAT-LABEL: caller_float__callee_float_vararg:
; SOFTFLOAT:       @ %bb.0:
; SOFTFLOAT-NEXT:    movs r0, #0
; SOFTFLOAT-NEXT:    b callee_float_vararg
;
; HF-NOTAIL-LABEL: caller_float__callee_float_vararg:
; HF-NOTAIL:       @ %bb.0:
; HF-NOTAIL-NEXT:    .save {r7, lr}
; HF-NOTAIL-NEXT:    push {r7, lr}
; HF-NOTAIL-NEXT:    movs r0, #0
; HF-NOTAIL-NEXT:    bl callee_float_vararg
; HF-NOTAIL-NEXT:    vmov s0, r0
; HF-NOTAIL-NEXT:    pop {r7, pc}
  %r = tail call float (i32, ...) @callee_float_vararg(i32 0)
  ret float %r
}

define float @caller_float_vararg__callee_float(i32, ...) {
; CHECK-LABEL: caller_float_vararg__callee_float:
; CHECK:       @ %bb.0:
; CHECK-NEXT:    .save {r7, lr}
; CHECK-NEXT:    push {r7, lr}
; CHECK-NEXT:    bl callee_float
; CHECK-NEXT:    vmov r0, s0
; CHECK-NEXT:    pop {r7, pc}
;
; SOFTFLOAT-LABEL: caller_float_vararg__callee_float:
; SOFTFLOAT:       @ %bb.0:
; SOFTFLOAT-NEXT:    b callee_float
;
; HF-NOTAIL-LABEL: caller_float_vararg__callee_float:
; HF-NOTAIL:       @ %bb.0:
; HF-NOTAIL-NEXT:    .save {r7, lr}
; HF-NOTAIL-NEXT:    push {r7, lr}
; HF-NOTAIL-NEXT:    bl callee_float
; HF-NOTAIL-NEXT:    vmov r0, s0
; HF-NOTAIL-NEXT:    pop {r7, pc}
  %r = tail call float @callee_float()
  ret float %r
}

define float @caller_float_vararg__callee_float_vararg(i32, ...) {
; CHECK-LABEL: caller_float_vararg__callee_float_vararg:
; CHECK:       @ %bb.0:
; CHECK-NEXT:    movs r0, #0
; CHECK-NEXT:    b callee_float_vararg
;
; SOFTFLOAT-LABEL: caller_float_vararg__callee_float_vararg:
; SOFTFLOAT:       @ %bb.0:
; SOFTFLOAT-NEXT:    movs r0, #0
; SOFTFLOAT-NEXT:    b callee_float_vararg
;
; HF-NOTAIL-LABEL: caller_float_vararg__callee_float_vararg:
; HF-NOTAIL:       @ %bb.0:
; HF-NOTAIL-NEXT:    .save {r7, lr}
; HF-NOTAIL-NEXT:    push {r7, lr}
; HF-NOTAIL-NEXT:    movs r0, #0
; HF-NOTAIL-NEXT:    bl callee_float_vararg
; HF-NOTAIL-NEXT:    pop {r7, pc}
  %r = tail call float (i32, ...) @callee_float_vararg(i32 0)
  ret float %r
}

define i32 @caller_int__callee_int() {
; CHECK-LABEL: caller_int__callee_int:
; CHECK:       @ %bb.0:
; CHECK-NEXT:    b callee_int
;
; SOFTFLOAT-LABEL: caller_int__callee_int:
; SOFTFLOAT:       @ %bb.0:
; SOFTFLOAT-NEXT:    b callee_int
;
; HF-NOTAIL-LABEL: caller_int__callee_int:
; HF-NOTAIL:       @ %bb.0:
; HF-NOTAIL-NEXT:    .save {r7, lr}
; HF-NOTAIL-NEXT:    push {r7, lr}
; HF-NOTAIL-NEXT:    bl callee_int
; HF-NOTAIL-NEXT:    pop {r7, pc}
  %r = tail call i32 @callee_int()
  ret i32 %r
}

define i32 @caller_int__callee_int_vararg() {
; CHECK-LABEL: caller_int__callee_int_vararg:
; CHECK:       @ %bb.0:
; CHECK-NEXT:    movs r0, #0
; CHECK-NEXT:    b callee_int_vararg
;
; SOFTFLOAT-LABEL: caller_int__callee_int_vararg:
; SOFTFLOAT:       @ %bb.0:
; SOFTFLOAT-NEXT:    movs r0, #0
; SOFTFLOAT-NEXT:    b callee_int_vararg
;
; HF-NOTAIL-LABEL: caller_int__callee_int_vararg:
; HF-NOTAIL:       @ %bb.0:
; HF-NOTAIL-NEXT:    .save {r7, lr}
; HF-NOTAIL-NEXT:    push {r7, lr}
; HF-NOTAIL-NEXT:    movs r0, #0
; HF-NOTAIL-NEXT:    bl callee_int_vararg
; HF-NOTAIL-NEXT:    pop {r7, pc}
  %r = tail call i32 (i32, ...) @callee_int_vararg(i32 0)
  ret i32 %r
}

define i32 @caller_int_vararg__callee_int(i32, ...) {
; CHECK-LABEL: caller_int_vararg__callee_int:
; CHECK:       @ %bb.0:
; CHECK-NEXT:    b callee_int
;
; SOFTFLOAT-LABEL: caller_int_vararg__callee_int:
; SOFTFLOAT:       @ %bb.0:
; SOFTFLOAT-NEXT:    b callee_int
;
; HF-NOTAIL-LABEL: caller_int_vararg__callee_int:
; HF-NOTAIL:       @ %bb.0:
; HF-NOTAIL-NEXT:    .save {r7, lr}
; HF-NOTAIL-NEXT:    push {r7, lr}
; HF-NOTAIL-NEXT:    bl callee_int
; HF-NOTAIL-NEXT:    pop {r7, pc}
  %r = tail call i32 @callee_int()
  ret i32 %r
}

define i32 @caller_int_vararg__callee_int_vararg(i32, ...) {
; CHECK-LABEL: caller_int_vararg__callee_int_vararg:
; CHECK:       @ %bb.0:
; CHECK-NEXT:    movs r0, #0
; CHECK-NEXT:    b callee_int_vararg
;
; SOFTFLOAT-LABEL: caller_int_vararg__callee_int_vararg:
; SOFTFLOAT:       @ %bb.0:
; SOFTFLOAT-NEXT:    movs r0, #0
; SOFTFLOAT-NEXT:    b callee_int_vararg
;
; HF-NOTAIL-LABEL: caller_int_vararg__callee_int_vararg:
; HF-NOTAIL:       @ %bb.0:
; HF-NOTAIL-NEXT:    .save {r7, lr}
; HF-NOTAIL-NEXT:    push {r7, lr}
; HF-NOTAIL-NEXT:    movs r0, #0
; HF-NOTAIL-NEXT:    bl callee_int_vararg
; HF-NOTAIL-NEXT:    pop {r7, pc}
  %r = tail call i32 (i32, ...) @callee_int_vararg(i32 0)
  ret i32 %r
}