mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-11-02 07:17:36 +00:00
[ARM] Enable DP copy, load and store instructions for FPv4-SP
The FPv4-SP floating-point unit is generally referred to as single-precision only, but it does have double-precision registers and load, store and GPR<->DPR move instructions which operate on them. This patch enables the use of these registers, the main advantage of which is that we now comply with the AAPCS-VFP calling convention. This partially reverts r209650, which added some AAPCS-VFP support, but did not handle return values or alignment of double arguments in registers. This patch also adds tests for Thumb2 code generation for floating-point instructions and intrinsics, which previously only existed for ARM. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@216172 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@@ -54,12 +54,11 @@ define arm_aapcs_vfpcc void @test_1double({ double } %a) {
|
||||
; CHECK: bl test_1double
|
||||
|
||||
; CHECK-M4F-LABEL: test_1double:
|
||||
; CHECK-M4F: movs [[ONEHI:r[0-9]+]], #0
|
||||
; CHECK-M4F: movs [[ONELO:r[0-9]+]], #0
|
||||
; CHECK-M4F: movt [[ONEHI]], #16368
|
||||
; CHECK-M4F-DAG: vmov s0, [[ONELO]]
|
||||
; CHECK-M4F-DAG: vmov s1, [[ONEHI]]
|
||||
; CHECK-M4F: vldr d0, [[CP_LABEL:.*]]
|
||||
; CHECK-M4F: bl test_1double
|
||||
; CHECK-M4F: [[CP_LABEL]]
|
||||
; CHECK-M4F-NEXT: .long 0
|
||||
; CHECK-M4F-NEXT: .long 1072693248
|
||||
|
||||
call arm_aapcs_vfpcc void @test_1double({ double } { double 1.0 })
|
||||
ret void
|
||||
@@ -76,11 +75,10 @@ define arm_aapcs_vfpcc void @test_1double_nosplit([4 x float], [4 x double], [3
|
||||
; CHECK: bl test_1double_nosplit
|
||||
|
||||
; CHECK-M4F-LABEL: test_1double_nosplit:
|
||||
; CHECK-M4F: movs [[ONELO:r[0-9]+]], #0
|
||||
; CHECK-M4F: movs [[ONEHI:r[0-9]+]], #0
|
||||
; CHECK-M4F: movs [[ONELO:r[0-9]+]], #0
|
||||
; CHECK-M4F: movt [[ONEHI]], #16368
|
||||
; CHECK-M4F-DAG: str [[ONELO]], [sp]
|
||||
; CHECK-M4F-DAG: str [[ONEHI]], [sp, #4]
|
||||
; CHECK-M4F: strd [[ONELO]], [[ONEHI]], [sp]
|
||||
; CHECK-M4F: bl test_1double_nosplit
|
||||
call arm_aapcs_vfpcc void @test_1double_nosplit([4 x float] undef, [4 x double] undef, [3 x float] undef, double 1.0)
|
||||
ret void
|
||||
@@ -98,11 +96,10 @@ define arm_aapcs_vfpcc void @test_1double_misaligned([4 x double], [4 x double],
|
||||
; CHECK-DAG: strd [[ONELO]], [[ONEHI]], [sp, #8]
|
||||
|
||||
; CHECK-M4F-LABEL: test_1double_misaligned:
|
||||
; CHECK-M4F: movs [[ONELO:r[0-9]+]], #0
|
||||
; CHECK-M4F: movs [[ONEHI:r[0-9]+]], #0
|
||||
; CHECK-M4F: movs [[ONELO:r[0-9]+]], #0
|
||||
; CHECK-M4F: movt [[ONEHI]], #16368
|
||||
; CHECK-M4F-DAG: str [[ONELO]], [sp, #8]
|
||||
; CHECK-M4F-DAG: str [[ONEHI]], [sp, #12]
|
||||
; CHECK-M4F: strd [[ONELO]], [[ONEHI]], [sp, #8]
|
||||
; CHECK-M4F: bl test_1double_misaligned
|
||||
|
||||
ret void
|
||||
|
||||
@@ -20,5 +20,5 @@ define double @double_op(double %lhs, double %rhs) {
|
||||
; CHECK-M3: bl ___adddf3
|
||||
|
||||
; CHECK-M4-LABEL: double_op:
|
||||
; CHECK-M4: bl ___adddf3
|
||||
; CHECK-M4: {{(blx|b.w)}} ___adddf3
|
||||
}
|
||||
|
||||
50
test/CodeGen/Thumb2/aapcs.ll
Normal file
50
test/CodeGen/Thumb2/aapcs.ll
Normal file
@@ -0,0 +1,50 @@
|
||||
; RUN: llc < %s -mtriple=thumbv7-none-eabi -mcpu=cortex-m4 -mattr=-vfp2 | FileCheck %s -check-prefix=CHECK -check-prefix=SOFT
|
||||
; RUN: llc < %s -mtriple=thumbv7-none-eabihf -mcpu=cortex-m4 -mattr=+vfp4,+fp-only-sp | FileCheck %s -check-prefix=CHECK -check-prefix=HARD -check-prefix=SP
|
||||
; RUN: llc < %s -mtriple=thumbv7-none-eabihf -mcpu=cortex-a8 -mattr=+vfp3 | FileCheck %s -check-prefix=CHECK -check-prefix=HARD -check-prefix=DP
|
||||
|
||||
define float @float_in_reg(float %a, float %b) {
|
||||
entry:
|
||||
; CHECK-LABEL: float_in_reg:
|
||||
; SOFT: mov r0, r1
|
||||
; HARD: vmov.f32 s0, s1
|
||||
; CHECK-NEXT: bx lr
|
||||
ret float %b
|
||||
}
|
||||
|
||||
define double @double_in_reg(double %a, double %b) {
|
||||
entry:
|
||||
; CHECK-LABEL: double_in_reg:
|
||||
; SOFT: mov r0, r2
|
||||
; SOFT: mov r1, r3
|
||||
; SP: vmov.f32 s0, s2
|
||||
; SP: vmov.f32 s1, s3
|
||||
; DP: vmov.f64 d0, d1
|
||||
; CHECK-NEXT: bx lr
|
||||
ret double %b
|
||||
}
|
||||
|
||||
define float @float_on_stack(double %a, double %b, double %c, double %d, double %e, double %f, double %g, double %h, float %i) {
|
||||
; CHECK-LABEL: float_on_stack:
|
||||
; SOFT: ldr r0, [sp, #48]
|
||||
; HARD: vldr s0, [sp]
|
||||
; CHECK-NEXT: bx lr
|
||||
ret float %i
|
||||
}
|
||||
|
||||
define double @double_on_stack(double %a, double %b, double %c, double %d, double %e, double %f, double %g, double %h, double %i) {
|
||||
; CHECK-LABEL: double_on_stack:
|
||||
; SOFT: ldr r0, [sp, #48]
|
||||
; SOFT: ldr r1, [sp, #52]
|
||||
; HARD: vldr d0, [sp]
|
||||
; CHECK-NEXT: bx lr
|
||||
ret double %i
|
||||
}
|
||||
|
||||
define double @double_not_split(double %a, double %b, double %c, double %d, double %e, double %f, double %g, float %h, double %i) {
|
||||
; CHECK-LABEL: double_not_split:
|
||||
; SOFT: ldr r0, [sp, #48]
|
||||
; SOFT: ldr r1, [sp, #52]
|
||||
; HARD: vldr d0, [sp]
|
||||
; CHECK-NEXT: bx lr
|
||||
ret double %i
|
||||
}
|
||||
@@ -18,7 +18,7 @@ entry:
|
||||
; CHECK-LABEL: bar:
|
||||
%0 = fmul double %a, %b
|
||||
; CORTEXM3: bl ___muldf3
|
||||
; CORTEXM4: bl ___muldf3
|
||||
; CORTEXM4: {{bl|b.w}} ___muldf3
|
||||
; CORTEXA8: vmul.f64 d
|
||||
ret double %0
|
||||
}
|
||||
|
||||
300
test/CodeGen/Thumb2/float-cmp.ll
Normal file
300
test/CodeGen/Thumb2/float-cmp.ll
Normal file
@@ -0,0 +1,300 @@
|
||||
; RUN: llc < %s -mtriple=thumbv7-none-eabi -mcpu=cortex-m3 | FileCheck %s -check-prefix=CHECK -check-prefix=NONE
|
||||
; RUN: llc < %s -mtriple=thumbv7-none-eabihf -mcpu=cortex-m4 | FileCheck %s -check-prefix=CHECK -check-prefix=HARD -check-prefix=SP
|
||||
; RUN: llc < %s -mtriple=thumbv7-none-eabihf -mcpu=cortex-a8 | FileCheck %s -check-prefix=CHECK -check-prefix=HARD -check-prefix=DP
|
||||
|
||||
|
||||
|
||||
define i1 @cmp_f_false(float %a, float %b) {
|
||||
; CHECK-LABEL: cmp_f_false:
|
||||
; NONE: movs r0, #0
|
||||
; HARD: movs r0, #0
|
||||
%1 = fcmp false float %a, %b
|
||||
ret i1 %1
|
||||
}
|
||||
define i1 @cmp_f_oeq(float %a, float %b) {
|
||||
; CHECK-LABEL: cmp_f_oeq:
|
||||
; NONE: bl __aeabi_fcmpeq
|
||||
; HARD: vcmpe.f32
|
||||
; HARD: moveq r0, #1
|
||||
%1 = fcmp oeq float %a, %b
|
||||
ret i1 %1
|
||||
}
|
||||
define i1 @cmp_f_ogt(float %a, float %b) {
|
||||
; CHECK-LABEL: cmp_f_ogt:
|
||||
; NONE: bl __aeabi_fcmpgt
|
||||
; HARD: vcmpe.f32
|
||||
; HARD: movgt r0, #1
|
||||
%1 = fcmp ogt float %a, %b
|
||||
ret i1 %1
|
||||
}
|
||||
define i1 @cmp_f_oge(float %a, float %b) {
|
||||
; CHECK-LABEL: cmp_f_oge:
|
||||
; NONE: bl __aeabi_fcmpge
|
||||
; HARD: vcmpe.f32
|
||||
; HARD: movge r0, #1
|
||||
%1 = fcmp oge float %a, %b
|
||||
ret i1 %1
|
||||
}
|
||||
define i1 @cmp_f_olt(float %a, float %b) {
|
||||
; CHECK-LABEL: cmp_f_olt:
|
||||
; NONE: bl __aeabi_fcmplt
|
||||
; HARD: vcmpe.f32
|
||||
; HARD: movmi r0, #1
|
||||
%1 = fcmp olt float %a, %b
|
||||
ret i1 %1
|
||||
}
|
||||
define i1 @cmp_f_ole(float %a, float %b) {
|
||||
; CHECK-LABEL: cmp_f_ole:
|
||||
; NONE: bl __aeabi_fcmple
|
||||
; HARD: vcmpe.f32
|
||||
; HARD: movls r0, #1
|
||||
%1 = fcmp ole float %a, %b
|
||||
ret i1 %1
|
||||
}
|
||||
define i1 @cmp_f_one(float %a, float %b) {
|
||||
; CHECK-LABEL: cmp_f_one:
|
||||
; NONE: bl __aeabi_fcmpgt
|
||||
; NONE: bl __aeabi_fcmplt
|
||||
; HARD: vcmpe.f32
|
||||
; HARD: movmi r0, #1
|
||||
; HARD: movgt r0, #1
|
||||
%1 = fcmp one float %a, %b
|
||||
ret i1 %1
|
||||
}
|
||||
define i1 @cmp_f_ord(float %a, float %b) {
|
||||
; CHECK-LABEL: cmp_f_ord:
|
||||
; NONE: bl __aeabi_fcmpun
|
||||
; HARD: vcmpe.f32
|
||||
; HARD: movvc r0, #1
|
||||
%1 = fcmp ord float %a, %b
|
||||
ret i1 %1
|
||||
}define i1 @cmp_f_ueq(float %a, float %b) {
|
||||
; CHECK-LABEL: cmp_f_ueq:
|
||||
; NONE: bl __aeabi_fcmpeq
|
||||
; NONE: bl __aeabi_fcmpun
|
||||
; HARD: vcmpe.f32
|
||||
; HARD: moveq r0, #1
|
||||
; HARD: movvs r0, #1
|
||||
%1 = fcmp ueq float %a, %b
|
||||
ret i1 %1
|
||||
}
|
||||
define i1 @cmp_f_ugt(float %a, float %b) {
|
||||
; CHECK-LABEL: cmp_f_ugt:
|
||||
; NONE: bl __aeabi_fcmpgt
|
||||
; NONE: bl __aeabi_fcmpun
|
||||
; HARD: vcmpe.f32
|
||||
; HARD: movhi r0, #1
|
||||
%1 = fcmp ugt float %a, %b
|
||||
ret i1 %1
|
||||
}
|
||||
define i1 @cmp_f_uge(float %a, float %b) {
|
||||
; CHECK-LABEL: cmp_f_uge:
|
||||
; NONE: bl __aeabi_fcmpge
|
||||
; NONE: bl __aeabi_fcmpun
|
||||
; HARD: vcmpe.f32
|
||||
; HARD: movpl r0, #1
|
||||
%1 = fcmp uge float %a, %b
|
||||
ret i1 %1
|
||||
}
|
||||
define i1 @cmp_f_ult(float %a, float %b) {
|
||||
; CHECK-LABEL: cmp_f_ult:
|
||||
; NONE: bl __aeabi_fcmplt
|
||||
; NONE: bl __aeabi_fcmpun
|
||||
; HARD: vcmpe.f32
|
||||
; HARD: movlt r0, #1
|
||||
%1 = fcmp ult float %a, %b
|
||||
ret i1 %1
|
||||
}
|
||||
define i1 @cmp_f_ule(float %a, float %b) {
|
||||
; CHECK-LABEL: cmp_f_ule:
|
||||
; NONE: bl __aeabi_fcmple
|
||||
; NONE: bl __aeabi_fcmpun
|
||||
; HARD: vcmpe.f32
|
||||
; HARD: movle r0, #1
|
||||
%1 = fcmp ule float %a, %b
|
||||
ret i1 %1
|
||||
}
|
||||
define i1 @cmp_f_une(float %a, float %b) {
|
||||
; CHECK-LABEL: cmp_f_une:
|
||||
; NONE: bl __aeabi_fcmpeq
|
||||
; HARD: vcmpe.f32
|
||||
; HARD: movne r0, #1
|
||||
%1 = fcmp une float %a, %b
|
||||
ret i1 %1
|
||||
}
|
||||
define i1 @cmp_f_uno(float %a, float %b) {
|
||||
; CHECK-LABEL: cmp_f_uno:
|
||||
; NONE: bl __aeabi_fcmpun
|
||||
; HARD: vcmpe.f32
|
||||
; HARD: movvs r0, #1
|
||||
%1 = fcmp uno float %a, %b
|
||||
ret i1 %1
|
||||
}
|
||||
define i1 @cmp_f_true(float %a, float %b) {
|
||||
; CHECK-LABEL: cmp_f_true:
|
||||
; NONE: movs r0, #1
|
||||
; HARD: movs r0, #1
|
||||
%1 = fcmp true float %a, %b
|
||||
ret i1 %1
|
||||
}
|
||||
|
||||
define i1 @cmp_d_false(double %a, double %b) {
|
||||
; CHECK-LABEL: cmp_d_false:
|
||||
; NONE: movs r0, #0
|
||||
; HARD: movs r0, #0
|
||||
%1 = fcmp false double %a, %b
|
||||
ret i1 %1
|
||||
}
|
||||
define i1 @cmp_d_oeq(double %a, double %b) {
|
||||
; CHECK-LABEL: cmp_d_oeq:
|
||||
; NONE: bl __aeabi_dcmpeq
|
||||
; SP: bl __aeabi_dcmpeq
|
||||
; DP: vcmpe.f64
|
||||
; DP: moveq r0, #1
|
||||
%1 = fcmp oeq double %a, %b
|
||||
ret i1 %1
|
||||
}
|
||||
define i1 @cmp_d_ogt(double %a, double %b) {
|
||||
; CHECK-LABEL: cmp_d_ogt:
|
||||
; NONE: bl __aeabi_dcmpgt
|
||||
; SP: bl __aeabi_dcmpgt
|
||||
; DP: vcmpe.f64
|
||||
; DP: movgt r0, #1
|
||||
%1 = fcmp ogt double %a, %b
|
||||
ret i1 %1
|
||||
}
|
||||
define i1 @cmp_d_oge(double %a, double %b) {
|
||||
; CHECK-LABEL: cmp_d_oge:
|
||||
; NONE: bl __aeabi_dcmpge
|
||||
; SP: bl __aeabi_dcmpge
|
||||
; DP: vcmpe.f64
|
||||
; DP: movge r0, #1
|
||||
%1 = fcmp oge double %a, %b
|
||||
ret i1 %1
|
||||
}
|
||||
define i1 @cmp_d_olt(double %a, double %b) {
|
||||
; CHECK-LABEL: cmp_d_olt:
|
||||
; NONE: bl __aeabi_dcmplt
|
||||
; SP: bl __aeabi_dcmplt
|
||||
; DP: vcmpe.f64
|
||||
; DP: movmi r0, #1
|
||||
%1 = fcmp olt double %a, %b
|
||||
ret i1 %1
|
||||
}
|
||||
define i1 @cmp_d_ole(double %a, double %b) {
|
||||
; CHECK-LABEL: cmp_d_ole:
|
||||
; NONE: bl __aeabi_dcmple
|
||||
; SP: bl __aeabi_dcmple
|
||||
; DP: vcmpe.f64
|
||||
; DP: movls r0, #1
|
||||
%1 = fcmp ole double %a, %b
|
||||
ret i1 %1
|
||||
}
|
||||
define i1 @cmp_d_one(double %a, double %b) {
|
||||
; CHECK-LABEL: cmp_d_one:
|
||||
; NONE: bl __aeabi_dcmpgt
|
||||
; NONE: bl __aeabi_dcmplt
|
||||
; SP: bl __aeabi_dcmpgt
|
||||
; SP: bl __aeabi_dcmplt
|
||||
; DP: vcmpe.f64
|
||||
; DP: movmi r0, #1
|
||||
; DP: movgt r0, #1
|
||||
%1 = fcmp one double %a, %b
|
||||
ret i1 %1
|
||||
}
|
||||
define i1 @cmp_d_ord(double %a, double %b) {
|
||||
; CHECK-LABEL: cmp_d_ord:
|
||||
; NONE: bl __aeabi_dcmpun
|
||||
; SP: bl __aeabi_dcmpun
|
||||
; DP: vcmpe.f64
|
||||
; DP: movvc r0, #1
|
||||
%1 = fcmp ord double %a, %b
|
||||
ret i1 %1
|
||||
}
|
||||
define i1 @cmp_d_ugt(double %a, double %b) {
|
||||
; CHECK-LABEL: cmp_d_ugt:
|
||||
; NONE: bl __aeabi_dcmpgt
|
||||
; NONE: bl __aeabi_dcmpun
|
||||
; SP: bl __aeabi_dcmpgt
|
||||
; SP: bl __aeabi_dcmpun
|
||||
; DP: vcmpe.f64
|
||||
; DP: movhi r0, #1
|
||||
%1 = fcmp ugt double %a, %b
|
||||
ret i1 %1
|
||||
}
|
||||
|
||||
define i1 @cmp_d_ult(double %a, double %b) {
|
||||
; CHECK-LABEL: cmp_d_ult:
|
||||
; NONE: bl __aeabi_dcmplt
|
||||
; NONE: bl __aeabi_dcmpun
|
||||
; SP: bl __aeabi_dcmplt
|
||||
; SP: bl __aeabi_dcmpun
|
||||
; DP: vcmpe.f64
|
||||
; DP: movlt r0, #1
|
||||
%1 = fcmp ult double %a, %b
|
||||
ret i1 %1
|
||||
}
|
||||
|
||||
|
||||
define i1 @cmp_d_uno(double %a, double %b) {
|
||||
; CHECK-LABEL: cmp_d_uno:
|
||||
; NONE: bl __aeabi_dcmpun
|
||||
; SP: bl __aeabi_dcmpun
|
||||
; DP: vcmpe.f64
|
||||
; DP: movvs r0, #1
|
||||
%1 = fcmp uno double %a, %b
|
||||
ret i1 %1
|
||||
}
|
||||
define i1 @cmp_d_true(double %a, double %b) {
|
||||
; CHECK-LABEL: cmp_d_true:
|
||||
; NONE: movs r0, #1
|
||||
; HARD: movs r0, #1
|
||||
%1 = fcmp true double %a, %b
|
||||
ret i1 %1
|
||||
}
|
||||
define i1 @cmp_d_ueq(double %a, double %b) {
|
||||
; CHECK-LABEL: cmp_d_ueq:
|
||||
; NONE: bl __aeabi_dcmpeq
|
||||
; NONE: bl __aeabi_dcmpun
|
||||
; SP: bl __aeabi_dcmpeq
|
||||
; SP: bl __aeabi_dcmpun
|
||||
; DP: vcmpe.f64
|
||||
; DP: moveq r0, #1
|
||||
; DP: movvs r0, #1
|
||||
%1 = fcmp ueq double %a, %b
|
||||
ret i1 %1
|
||||
}
|
||||
|
||||
define i1 @cmp_d_uge(double %a, double %b) {
|
||||
; CHECK-LABEL: cmp_d_uge:
|
||||
; NONE: bl __aeabi_dcmpge
|
||||
; NONE: bl __aeabi_dcmpun
|
||||
; SP: bl __aeabi_dcmpge
|
||||
; SP: bl __aeabi_dcmpun
|
||||
; DP: vcmpe.f64
|
||||
; DP: movpl r0, #1
|
||||
%1 = fcmp uge double %a, %b
|
||||
ret i1 %1
|
||||
}
|
||||
|
||||
define i1 @cmp_d_ule(double %a, double %b) {
|
||||
; CHECK-LABEL: cmp_d_ule:
|
||||
; NONE: bl __aeabi_dcmple
|
||||
; NONE: bl __aeabi_dcmpun
|
||||
; SP: bl __aeabi_dcmple
|
||||
; SP: bl __aeabi_dcmpun
|
||||
; DP: vcmpe.f64
|
||||
; DP: movle r0, #1
|
||||
%1 = fcmp ule double %a, %b
|
||||
ret i1 %1
|
||||
}
|
||||
|
||||
define i1 @cmp_d_une(double %a, double %b) {
|
||||
; CHECK-LABEL: cmp_d_une:
|
||||
; NONE: bl __aeabi_dcmpeq
|
||||
; SP: bl __aeabi_dcmpeq
|
||||
; DP: vcmpe.f64
|
||||
; DP: movne r0, #1
|
||||
%1 = fcmp une double %a, %b
|
||||
ret i1 %1
|
||||
}
|
||||
214
test/CodeGen/Thumb2/float-intrinsics-double.ll
Normal file
214
test/CodeGen/Thumb2/float-intrinsics-double.ll
Normal file
@@ -0,0 +1,214 @@
|
||||
; RUN: llc < %s -mtriple=thumbv7-none-eabi -mcpu=cortex-m3 | FileCheck %s -check-prefix=CHECK -check-prefix=SOFT -check-prefix=NONE
|
||||
; RUN: llc < %s -mtriple=thumbv7-none-eabihf -mcpu=cortex-m4 | FileCheck %s -check-prefix=CHECK -check-prefix=SOFT -check-prefix=SP
|
||||
; RUN: llc < %s -mtriple=thumbv7-none-eabihf -mcpu=cortex-a7 | FileCheck %s -check-prefix=CHECK -check-prefix=HARD -check-prefix=DP
|
||||
|
||||
declare double @llvm.sqrt.f64(double %Val)
|
||||
define double @sqrt_d(double %a) {
|
||||
; CHECK-LABEL: sqrt_d:
|
||||
; SOFT: {{(bl|b)}} sqrt
|
||||
; HARD: vsqrt.f64 d0, d0
|
||||
%1 = call double @llvm.sqrt.f64(double %a)
|
||||
ret double %1
|
||||
}
|
||||
|
||||
declare double @llvm.powi.f64(double %Val, i32 %power)
|
||||
define double @powi_d(double %a, i32 %b) {
|
||||
; CHECK-LABEL: powi_d:
|
||||
; SOFT: {{(bl|b)}} __powidf2
|
||||
; HARD: b __powidf2
|
||||
%1 = call double @llvm.powi.f64(double %a, i32 %b)
|
||||
ret double %1
|
||||
}
|
||||
|
||||
declare double @llvm.sin.f64(double %Val)
|
||||
define double @sin_d(double %a) {
|
||||
; CHECK-LABEL: sin_d:
|
||||
; SOFT: {{(bl|b)}} sin
|
||||
; HARD: b sin
|
||||
%1 = call double @llvm.sin.f64(double %a)
|
||||
ret double %1
|
||||
}
|
||||
|
||||
declare double @llvm.cos.f64(double %Val)
|
||||
define double @cos_d(double %a) {
|
||||
; CHECK-LABEL: cos_d:
|
||||
; SOFT: {{(bl|b)}} cos
|
||||
; HARD: b cos
|
||||
%1 = call double @llvm.cos.f64(double %a)
|
||||
ret double %1
|
||||
}
|
||||
|
||||
declare double @llvm.pow.f64(double %Val, double %power)
|
||||
define double @pow_d(double %a, double %b) {
|
||||
; CHECK-LABEL: pow_d:
|
||||
; SOFT: {{(bl|b)}} pow
|
||||
; HARD: b pow
|
||||
%1 = call double @llvm.pow.f64(double %a, double %b)
|
||||
ret double %1
|
||||
}
|
||||
|
||||
declare double @llvm.exp.f64(double %Val)
|
||||
define double @exp_d(double %a) {
|
||||
; CHECK-LABEL: exp_d:
|
||||
; SOFT: {{(bl|b)}} exp
|
||||
; HARD: b exp
|
||||
%1 = call double @llvm.exp.f64(double %a)
|
||||
ret double %1
|
||||
}
|
||||
|
||||
declare double @llvm.exp2.f64(double %Val)
|
||||
define double @exp2_d(double %a) {
|
||||
; CHECK-LABEL: exp2_d:
|
||||
; SOFT: {{(bl|b)}} exp2
|
||||
; HARD: b exp2
|
||||
%1 = call double @llvm.exp2.f64(double %a)
|
||||
ret double %1
|
||||
}
|
||||
|
||||
declare double @llvm.log.f64(double %Val)
|
||||
define double @log_d(double %a) {
|
||||
; CHECK-LABEL: log_d:
|
||||
; SOFT: {{(bl|b)}} log
|
||||
; HARD: b log
|
||||
%1 = call double @llvm.log.f64(double %a)
|
||||
ret double %1
|
||||
}
|
||||
|
||||
declare double @llvm.log10.f64(double %Val)
|
||||
define double @log10_d(double %a) {
|
||||
; CHECK-LABEL: log10_d:
|
||||
; SOFT: {{(bl|b)}} log10
|
||||
; HARD: b log10
|
||||
%1 = call double @llvm.log10.f64(double %a)
|
||||
ret double %1
|
||||
}
|
||||
|
||||
declare double @llvm.log2.f64(double %Val)
|
||||
define double @log2_d(double %a) {
|
||||
; CHECK-LABEL: log2_d:
|
||||
; SOFT: {{(bl|b)}} log2
|
||||
; HARD: b log2
|
||||
%1 = call double @llvm.log2.f64(double %a)
|
||||
ret double %1
|
||||
}
|
||||
|
||||
declare double @llvm.fma.f64(double %a, double %b, double %c)
|
||||
define double @fma_d(double %a, double %b, double %c) {
|
||||
; CHECK-LABEL: fma_d:
|
||||
; SOFT: {{(bl|b)}} fma
|
||||
; HARD: vfma.f64
|
||||
%1 = call double @llvm.fma.f64(double %a, double %b, double %c)
|
||||
ret double %1
|
||||
}
|
||||
|
||||
; FIXME: the FPv4-SP version is less efficient than the no-FPU version
|
||||
declare double @llvm.fabs.f64(double %Val)
|
||||
define double @abs_d(double %a) {
|
||||
; CHECK-LABEL: abs_d:
|
||||
; NONE: bic r1, r1, #-2147483648
|
||||
; SP: bl __aeabi_dcmpgt
|
||||
; SP: bl __aeabi_dcmpun
|
||||
; SP: bl __aeabi_dsub
|
||||
; DP: vabs.f64 d0, d0
|
||||
%1 = call double @llvm.fabs.f64(double %a)
|
||||
ret double %1
|
||||
}
|
||||
|
||||
declare double @llvm.copysign.f64(double %Mag, double %Sgn)
|
||||
define double @copysign_d(double %a, double %b) {
|
||||
; CHECK-LABEL: copysign_d:
|
||||
; SOFT: lsrs [[REG:r[0-9]+]], r3, #31
|
||||
; SOFT: bfi r1, [[REG]], #31, #1
|
||||
; HARD: vmov.i32 [[REG:d[0-9]+]], #0x80000000
|
||||
; HARD: vshl.i64 [[REG]], [[REG]], #32
|
||||
; HARD: vbsl [[REG]], d
|
||||
%1 = call double @llvm.copysign.f64(double %a, double %b)
|
||||
ret double %1
|
||||
}
|
||||
|
||||
declare double @llvm.floor.f64(double %Val)
|
||||
define double @floor_d(double %a) {
|
||||
; CHECK-LABEL: floor_d:
|
||||
; SOFT: {{(bl|b)}} floor
|
||||
; HARD: b floor
|
||||
%1 = call double @llvm.floor.f64(double %a)
|
||||
ret double %1
|
||||
}
|
||||
|
||||
declare double @llvm.ceil.f64(double %Val)
|
||||
define double @ceil_d(double %a) {
|
||||
; CHECK-LABEL: ceil_d:
|
||||
; SOFT: {{(bl|b)}} ceil
|
||||
; HARD: b ceil
|
||||
%1 = call double @llvm.ceil.f64(double %a)
|
||||
ret double %1
|
||||
}
|
||||
|
||||
declare double @llvm.trunc.f64(double %Val)
|
||||
define double @trunc_d(double %a) {
|
||||
; CHECK-LABEL: trunc_d:
|
||||
; SOFT: {{(bl|b)}} trunc
|
||||
; HARD: b trunc
|
||||
%1 = call double @llvm.trunc.f64(double %a)
|
||||
ret double %1
|
||||
}
|
||||
|
||||
declare double @llvm.rint.f64(double %Val)
|
||||
define double @rint_d(double %a) {
|
||||
; CHECK-LABEL: rint_d:
|
||||
; SOFT: {{(bl|b)}} rint
|
||||
; HARD: b rint
|
||||
%1 = call double @llvm.rint.f64(double %a)
|
||||
ret double %1
|
||||
}
|
||||
|
||||
declare double @llvm.nearbyint.f64(double %Val)
|
||||
define double @nearbyint_d(double %a) {
|
||||
; CHECK-LABEL: nearbyint_d:
|
||||
; SOFT: {{(bl|b)}} nearbyint
|
||||
; HARD: b nearbyint
|
||||
%1 = call double @llvm.nearbyint.f64(double %a)
|
||||
ret double %1
|
||||
}
|
||||
|
||||
declare double @llvm.round.f64(double %Val)
|
||||
define double @round_d(double %a) {
|
||||
; CHECK-LABEL: round_d:
|
||||
; SOFT: {{(bl|b)}} round
|
||||
; HARD: b round
|
||||
%1 = call double @llvm.round.f64(double %a)
|
||||
ret double %1
|
||||
}
|
||||
|
||||
declare double @llvm.fmuladd.f64(double %a, double %b, double %c)
|
||||
define double @fmuladd_d(double %a, double %b, double %c) {
|
||||
; CHECK-LABEL: fmuladd_d:
|
||||
; SOFT: bl __aeabi_dmul
|
||||
; SOFT: bl __aeabi_dadd
|
||||
; HARD: vmul.f64
|
||||
; HARD: vadd.f64
|
||||
%1 = call double @llvm.fmuladd.f64(double %a, double %b, double %c)
|
||||
ret double %1
|
||||
}
|
||||
|
||||
declare i16 @llvm.convert.to.fp16.f64(double %a)
|
||||
define i16 @d_to_h(double %a) {
|
||||
; CHECK-LABEL: d_to_h:
|
||||
; SOFT: bl __aeabi_d2h
|
||||
; HARD: bl __aeabi_d2h
|
||||
%1 = call i16 @llvm.convert.to.fp16.f64(double %a)
|
||||
ret i16 %1
|
||||
}
|
||||
|
||||
declare double @llvm.convert.from.fp16.f64(i16 %a)
|
||||
define double @h_to_d(i16 %a) {
|
||||
; CHECK-LABEL: h_to_d:
|
||||
; NONE: bl __gnu_h2f_ieee
|
||||
; NONE: bl __aeabi_f2d
|
||||
; SP: vcvtb.f32.f16
|
||||
; SP: bl __aeabi_f2d
|
||||
; DP: vcvtb.f32.f16
|
||||
; DP: vcvt.f64.f32
|
||||
%1 = call double @llvm.convert.from.fp16.f64(i16 %a)
|
||||
ret double %1
|
||||
}
|
||||
210
test/CodeGen/Thumb2/float-intrinsics-float.ll
Normal file
210
test/CodeGen/Thumb2/float-intrinsics-float.ll
Normal file
@@ -0,0 +1,210 @@
|
||||
; RUN: llc < %s -mtriple=thumbv7-none-eabi -mcpu=cortex-m3 | FileCheck %s -check-prefix=CHECK -check-prefix=SOFT -check-prefix=NONE
|
||||
; RUN: llc < %s -mtriple=thumbv7-none-eabihf -mcpu=cortex-m4 | FileCheck %s -check-prefix=CHECK -check-prefix=HARD -check-prefix=SP
|
||||
; RUN: llc < %s -mtriple=thumbv7-none-eabihf -mcpu=cortex-a7 | FileCheck %s -check-prefix=CHECK -check-prefix=HARD -check-prefix=DP
|
||||
|
||||
declare float @llvm.sqrt.f32(float %Val)
|
||||
define float @sqrt_f(float %a) {
|
||||
; CHECK-LABEL: sqrt_f:
|
||||
; SOFT: bl sqrtf
|
||||
; HARD: vsqrt.f32 s0, s0
|
||||
%1 = call float @llvm.sqrt.f32(float %a)
|
||||
ret float %1
|
||||
}
|
||||
|
||||
declare float @llvm.powi.f32(float %Val, i32 %power)
|
||||
define float @powi_f(float %a, i32 %b) {
|
||||
; CHECK-LABEL: powi_f:
|
||||
; SOFT: bl __powisf2
|
||||
; HARD: b __powisf2
|
||||
%1 = call float @llvm.powi.f32(float %a, i32 %b)
|
||||
ret float %1
|
||||
}
|
||||
|
||||
declare float @llvm.sin.f32(float %Val)
|
||||
define float @sin_f(float %a) {
|
||||
; CHECK-LABEL: sin_f:
|
||||
; SOFT: bl sinf
|
||||
; HARD: b sinf
|
||||
%1 = call float @llvm.sin.f32(float %a)
|
||||
ret float %1
|
||||
}
|
||||
|
||||
declare float @llvm.cos.f32(float %Val)
|
||||
define float @cos_f(float %a) {
|
||||
; CHECK-LABEL: cos_f:
|
||||
; SOFT: bl cosf
|
||||
; HARD: b cosf
|
||||
%1 = call float @llvm.cos.f32(float %a)
|
||||
ret float %1
|
||||
}
|
||||
|
||||
declare float @llvm.pow.f32(float %Val, float %power)
|
||||
define float @pow_f(float %a, float %b) {
|
||||
; CHECK-LABEL: pow_f:
|
||||
; SOFT: bl powf
|
||||
; HARD: b powf
|
||||
%1 = call float @llvm.pow.f32(float %a, float %b)
|
||||
ret float %1
|
||||
}
|
||||
|
||||
declare float @llvm.exp.f32(float %Val)
|
||||
define float @exp_f(float %a) {
|
||||
; CHECK-LABEL: exp_f:
|
||||
; SOFT: bl expf
|
||||
; HARD: b expf
|
||||
%1 = call float @llvm.exp.f32(float %a)
|
||||
ret float %1
|
||||
}
|
||||
|
||||
declare float @llvm.exp2.f32(float %Val)
|
||||
define float @exp2_f(float %a) {
|
||||
; CHECK-LABEL: exp2_f:
|
||||
; SOFT: bl exp2f
|
||||
; HARD: b exp2f
|
||||
%1 = call float @llvm.exp2.f32(float %a)
|
||||
ret float %1
|
||||
}
|
||||
|
||||
declare float @llvm.log.f32(float %Val)
|
||||
define float @log_f(float %a) {
|
||||
; CHECK-LABEL: log_f:
|
||||
; SOFT: bl logf
|
||||
; HARD: b logf
|
||||
%1 = call float @llvm.log.f32(float %a)
|
||||
ret float %1
|
||||
}
|
||||
|
||||
declare float @llvm.log10.f32(float %Val)
|
||||
define float @log10_f(float %a) {
|
||||
; CHECK-LABEL: log10_f:
|
||||
; SOFT: bl log10f
|
||||
; HARD: b log10f
|
||||
%1 = call float @llvm.log10.f32(float %a)
|
||||
ret float %1
|
||||
}
|
||||
|
||||
declare float @llvm.log2.f32(float %Val)
|
||||
define float @log2_f(float %a) {
|
||||
; CHECK-LABEL: log2_f:
|
||||
; SOFT: bl log2f
|
||||
; HARD: b log2f
|
||||
%1 = call float @llvm.log2.f32(float %a)
|
||||
ret float %1
|
||||
}
|
||||
|
||||
declare float @llvm.fma.f32(float %a, float %b, float %c)
|
||||
define float @fma_f(float %a, float %b, float %c) {
|
||||
; CHECK-LABEL: fma_f:
|
||||
; SOFT: bl fmaf
|
||||
; HARD: vfma.f32
|
||||
%1 = call float @llvm.fma.f32(float %a, float %b, float %c)
|
||||
ret float %1
|
||||
}
|
||||
|
||||
declare float @llvm.fabs.f32(float %Val)
|
||||
define float @abs_f(float %a) {
|
||||
; CHECK-LABEL: abs_f:
|
||||
; SOFT: bic r0, r0, #-2147483648
|
||||
; HARD: vabs.f32
|
||||
%1 = call float @llvm.fabs.f32(float %a)
|
||||
ret float %1
|
||||
}
|
||||
|
||||
declare float @llvm.copysign.f32(float %Mag, float %Sgn)
|
||||
define float @copysign_f(float %a, float %b) {
|
||||
; CHECK-LABEL: copysign_f:
|
||||
; NONE: lsrs [[REG:r[0-9]+]], r{{[0-9]+}}, #31
|
||||
; NONE: bfi r{{[0-9]+}}, [[REG]], #31, #1
|
||||
; SP: lsrs [[REG:r[0-9]+]], r{{[0-9]+}}, #31
|
||||
; SP: bfi r{{[0-9]+}}, [[REG]], #31, #1
|
||||
; DP: vmov.i32 [[REG:d[0-9]+]], #0x80000000
|
||||
; DP: vbsl [[REG]], d
|
||||
%1 = call float @llvm.copysign.f32(float %a, float %b)
|
||||
ret float %1
|
||||
}
|
||||
|
||||
declare float @llvm.floor.f32(float %Val)
|
||||
define float @floor_f(float %a) {
|
||||
; CHECK-LABEL: floor_f:
|
||||
; SOFT: bl floorf
|
||||
; HARD: b floorf
|
||||
%1 = call float @llvm.floor.f32(float %a)
|
||||
ret float %1
|
||||
}
|
||||
|
||||
declare float @llvm.ceil.f32(float %Val)
|
||||
define float @ceil_f(float %a) {
|
||||
; CHECK-LABEL: ceil_f:
|
||||
; SOFT: bl ceilf
|
||||
; HARD: b ceilf
|
||||
%1 = call float @llvm.ceil.f32(float %a)
|
||||
ret float %1
|
||||
}
|
||||
|
||||
declare float @llvm.trunc.f32(float %Val)
|
||||
define float @trunc_f(float %a) {
|
||||
; CHECK-LABEL: trunc_f:
|
||||
; SOFT: bl truncf
|
||||
; HARD: b truncf
|
||||
%1 = call float @llvm.trunc.f32(float %a)
|
||||
ret float %1
|
||||
}
|
||||
|
||||
declare float @llvm.rint.f32(float %Val)
|
||||
define float @rint_f(float %a) {
|
||||
; CHECK-LABEL: rint_f:
|
||||
; SOFT: bl rintf
|
||||
; HARD: b rintf
|
||||
%1 = call float @llvm.rint.f32(float %a)
|
||||
ret float %1
|
||||
}
|
||||
|
||||
declare float @llvm.nearbyint.f32(float %Val)
|
||||
define float @nearbyint_f(float %a) {
|
||||
; CHECK-LABEL: nearbyint_f:
|
||||
; SOFT: bl nearbyintf
|
||||
; HARD: b nearbyintf
|
||||
%1 = call float @llvm.nearbyint.f32(float %a)
|
||||
ret float %1
|
||||
}
|
||||
|
||||
declare float @llvm.round.f32(float %Val)
|
||||
define float @round_f(float %a) {
|
||||
; CHECK-LABEL: round_f:
|
||||
; SOFT: bl roundf
|
||||
; HARD: b roundf
|
||||
%1 = call float @llvm.round.f32(float %a)
|
||||
ret float %1
|
||||
}
|
||||
|
||||
; FIXME: why does cortex-m4 use vmla, while cortex-a7 uses vmul+vadd?
|
||||
; (these should be equivalent, even the rounding is the same)
|
||||
declare float @llvm.fmuladd.f32(float %a, float %b, float %c)
|
||||
define float @fmuladd_f(float %a, float %b, float %c) {
|
||||
; CHECK-LABEL: fmuladd_f:
|
||||
; SOFT: bl __aeabi_fmul
|
||||
; SOFT: bl __aeabi_fadd
|
||||
; SP: vmla.f32
|
||||
; DP: vmul.f32
|
||||
; DP: vadd.f32
|
||||
%1 = call float @llvm.fmuladd.f32(float %a, float %b, float %c)
|
||||
ret float %1
|
||||
}
|
||||
|
||||
declare i16 @llvm.convert.to.fp16.f32(float %a)
|
||||
define i16 @f_to_h(float %a) {
|
||||
; CHECK-LABEL: f_to_h:
|
||||
; SOFT: bl __gnu_f2h_ieee
|
||||
; HARD: vcvtb.f16.f32
|
||||
%1 = call i16 @llvm.convert.to.fp16.f32(float %a)
|
||||
ret i16 %1
|
||||
}
|
||||
|
||||
declare float @llvm.convert.from.fp16.f32(i16 %a)
|
||||
define float @h_to_f(i16 %a) {
|
||||
; CHECK-LABEL: h_to_f:
|
||||
; SOFT: bl __gnu_h2f_ieee
|
||||
; HARD: vcvtb.f32.f16
|
||||
%1 = call float @llvm.convert.from.fp16.f32(i16 %a)
|
||||
ret float %1
|
||||
}
|
||||
290
test/CodeGen/Thumb2/float-ops.ll
Normal file
290
test/CodeGen/Thumb2/float-ops.ll
Normal file
@@ -0,0 +1,290 @@
|
||||
; RUN: llc < %s -mtriple=thumbv7-none-eabi -mcpu=cortex-m3 | FileCheck %s -check-prefix=CHECK -check-prefix=NONE
|
||||
; RUN: llc < %s -mtriple=thumbv7-none-eabihf -mcpu=cortex-m4 | FileCheck %s -check-prefix=CHECK -check-prefix=HARD -check-prefix=SP
|
||||
; RUN: llc < %s -mtriple=thumbv7-none-eabihf -mcpu=cortex-a8 | FileCheck %s -check-prefix=CHECK -check-prefix=HARD -check-prefix=DP
|
||||
|
||||
define float @add_f(float %a, float %b) {
|
||||
entry:
|
||||
; CHECK-LABEL: add_f:
|
||||
; NONE: bl __aeabi_fadd
|
||||
; HARD: vadd.f32 s0, s0, s1
|
||||
%0 = fadd float %a, %b
|
||||
ret float %0
|
||||
}
|
||||
|
||||
define double @add_d(double %a, double %b) {
|
||||
entry:
|
||||
; CHECK-LABEL: add_d:
|
||||
; NONE: bl __aeabi_dadd
|
||||
; SP: bl __aeabi_dadd
|
||||
; DP: vadd.f64 d0, d0, d1
|
||||
%0 = fadd double %a, %b
|
||||
ret double %0
|
||||
}
|
||||
|
||||
define float @sub_f(float %a, float %b) {
|
||||
entry:
|
||||
; CHECK-LABEL: sub_f:
|
||||
; NONE: bl __aeabi_fsub
|
||||
; HARD: vsub.f32 s
|
||||
%0 = fsub float %a, %b
|
||||
ret float %0
|
||||
}
|
||||
|
||||
define double @sub_d(double %a, double %b) {
|
||||
entry:
|
||||
; CHECK-LABEL: sub_d:
|
||||
; NONE: bl __aeabi_dsub
|
||||
; SP: bl __aeabi_dsub
|
||||
; DP: vsub.f64 d0, d0, d1
|
||||
%0 = fsub double %a, %b
|
||||
ret double %0
|
||||
}
|
||||
|
||||
define float @mul_f(float %a, float %b) {
|
||||
entry:
|
||||
; CHECK-LABEL: mul_f:
|
||||
; NONE: bl __aeabi_fmul
|
||||
; HARD: vmul.f32 s
|
||||
%0 = fmul float %a, %b
|
||||
ret float %0
|
||||
}
|
||||
|
||||
define double @mul_d(double %a, double %b) {
|
||||
entry:
|
||||
; CHECK-LABEL: mul_d:
|
||||
; NONE: bl __aeabi_dmul
|
||||
; SP: bl __aeabi_dmul
|
||||
; DP: vmul.f64 d0, d0, d1
|
||||
%0 = fmul double %a, %b
|
||||
ret double %0
|
||||
}
|
||||
|
||||
define float @div_f(float %a, float %b) {
|
||||
entry:
|
||||
; CHECK-LABEL: div_f:
|
||||
; NONE: bl __aeabi_fdiv
|
||||
; HARD: vdiv.f32 s
|
||||
%0 = fdiv float %a, %b
|
||||
ret float %0
|
||||
}
|
||||
|
||||
define double @div_d(double %a, double %b) {
|
||||
entry:
|
||||
; CHECK-LABEL: div_d:
|
||||
; NONE: bl __aeabi_ddiv
|
||||
; SP: bl __aeabi_ddiv
|
||||
; DP: vdiv.f64 d0, d0, d1
|
||||
%0 = fdiv double %a, %b
|
||||
ret double %0
|
||||
}
|
||||
|
||||
define float @rem_f(float %a, float %b) {
|
||||
entry:
|
||||
; CHECK-LABEL: rem_f:
|
||||
; NONE: bl fmodf
|
||||
; HARD: b fmodf
|
||||
%0 = frem float %a, %b
|
||||
ret float %0
|
||||
}
|
||||
|
||||
define double @rem_d(double %a, double %b) {
|
||||
entry:
|
||||
; CHECK-LABEL: rem_d:
|
||||
; NONE: bl fmod
|
||||
; HARD: b fmod
|
||||
%0 = frem double %a, %b
|
||||
ret double %0
|
||||
}
|
||||
|
||||
define float @load_f(float* %a) {
|
||||
entry:
|
||||
; CHECK-LABEL: load_f:
|
||||
; NONE: ldr r0, [r0]
|
||||
; HARD: vldr s0, [r0]
|
||||
%0 = load float* %a, align 4
|
||||
ret float %0
|
||||
}
|
||||
|
||||
define double @load_d(double* %a) {
|
||||
entry:
|
||||
; CHECK-LABEL: load_d:
|
||||
; NONE: ldm.w r0, {r0, r1}
|
||||
; HARD: vldr d0, [r0]
|
||||
%0 = load double* %a, align 8
|
||||
ret double %0
|
||||
}
|
||||
|
||||
define void @store_f(float* %a, float %b) {
|
||||
entry:
|
||||
; CHECK-LABEL: store_f:
|
||||
; NONE: str r1, [r0]
|
||||
; HARD: vstr s0, [r0]
|
||||
store float %b, float* %a, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @store_d(double* %a, double %b) {
|
||||
entry:
|
||||
; CHECK-LABEL: store_d:
|
||||
; NONE: mov r1, r3
|
||||
; NONE: str r2, [r0]
|
||||
; NONE: str r1, [r0, #4]
|
||||
; HARD: vstr d0, [r0]
|
||||
store double %b, double* %a, align 8
|
||||
ret void
|
||||
}
|
||||
|
||||
define double @f_to_d(float %a) {
|
||||
; CHECK-LABEL: f_to_d:
|
||||
; NONE: bl __aeabi_f2d
|
||||
; SP: bl __aeabi_f2d
|
||||
; DP: vcvt.f64.f32 d0, s0
|
||||
%1 = fpext float %a to double
|
||||
ret double %1
|
||||
}
|
||||
|
||||
define float @d_to_f(double %a) {
|
||||
; CHECK-LABEL: d_to_f:
|
||||
; NONE: bl __aeabi_d2f
|
||||
; SP: bl __aeabi_d2f
|
||||
; DP: vcvt.f32.f64 s0, d0
|
||||
%1 = fptrunc double %a to float
|
||||
ret float %1
|
||||
}
|
||||
|
||||
define i32 @f_to_si(float %a) {
|
||||
; CHECK-LABEL: f_to_si:
|
||||
; NONE: bl __aeabi_f2iz
|
||||
; HARD: vcvt.s32.f32 s0, s0
|
||||
; HARD: vmov r0, s0
|
||||
%1 = fptosi float %a to i32
|
||||
ret i32 %1
|
||||
}
|
||||
|
||||
define i32 @d_to_si(double %a) {
|
||||
; CHECK-LABEL: d_to_si:
|
||||
; NONE: bl __aeabi_d2iz
|
||||
; SP: vmov r0, r1, d0
|
||||
; SP: bl __aeabi_d2iz
|
||||
; DP: vcvt.s32.f64 s0, d0
|
||||
; DP: vmov r0, s0
|
||||
%1 = fptosi double %a to i32
|
||||
ret i32 %1
|
||||
}
|
||||
|
||||
define i32 @f_to_ui(float %a) {
|
||||
; CHECK-LABEL: f_to_ui:
|
||||
; NONE: bl __aeabi_f2uiz
|
||||
; HARD: vcvt.u32.f32 s0, s0
|
||||
; HARD: vmov r0, s0
|
||||
%1 = fptoui float %a to i32
|
||||
ret i32 %1
|
||||
}
|
||||
|
||||
define i32 @d_to_ui(double %a) {
|
||||
; CHECK-LABEL: d_to_ui:
|
||||
; NONE: bl __aeabi_d2uiz
|
||||
; SP: vmov r0, r1, d0
|
||||
; SP: bl __aeabi_d2uiz
|
||||
; DP: vcvt.u32.f64 s0, d0
|
||||
; DP: vmov r0, s0
|
||||
%1 = fptoui double %a to i32
|
||||
ret i32 %1
|
||||
}
|
||||
|
||||
define float @si_to_f(i32 %a) {
|
||||
; CHECK-LABEL: si_to_f:
|
||||
; NONE: bl __aeabi_i2f
|
||||
; HARD: vcvt.f32.s32 s0, s0
|
||||
%1 = sitofp i32 %a to float
|
||||
ret float %1
|
||||
}
|
||||
|
||||
define double @si_to_d(i32 %a) {
|
||||
; CHECK-LABEL: si_to_d:
|
||||
; NONE: bl __aeabi_i2d
|
||||
; SP: bl __aeabi_i2d
|
||||
; DP: vcvt.f64.s32 d0, s0
|
||||
%1 = sitofp i32 %a to double
|
||||
ret double %1
|
||||
}
|
||||
|
||||
define float @ui_to_f(i32 %a) {
|
||||
; CHECK-LABEL: ui_to_f:
|
||||
; NONE: bl __aeabi_ui2f
|
||||
; HARD: vcvt.f32.u32 s0, s0
|
||||
%1 = uitofp i32 %a to float
|
||||
ret float %1
|
||||
}
|
||||
|
||||
define double @ui_to_d(i32 %a) {
|
||||
; CHECK-LABEL: ui_to_d:
|
||||
; NONE: bl __aeabi_ui2d
|
||||
; SP: bl __aeabi_ui2d
|
||||
; DP: vcvt.f64.u32 d0, s0
|
||||
%1 = uitofp i32 %a to double
|
||||
ret double %1
|
||||
}
|
||||
|
||||
define float @bitcast_i_to_f(i32 %a) {
|
||||
; CHECK-LABEL: bitcast_i_to_f:
|
||||
; NONE-NOT: mov
|
||||
; HARD: vmov s0, r0
|
||||
%1 = bitcast i32 %a to float
|
||||
ret float %1
|
||||
}
|
||||
|
||||
define double @bitcast_i_to_d(i64 %a) {
|
||||
; CHECK-LABEL: bitcast_i_to_d:
|
||||
; NONE-NOT: mov
|
||||
; HARD: vmov d0, r0, r1
|
||||
%1 = bitcast i64 %a to double
|
||||
ret double %1
|
||||
}
|
||||
|
||||
define i32 @bitcast_f_to_i(float %a) {
|
||||
; CHECK-LABEL: bitcast_f_to_i:
|
||||
; NONE-NOT: mov
|
||||
; HARD: vmov r0, s0
|
||||
%1 = bitcast float %a to i32
|
||||
ret i32 %1
|
||||
}
|
||||
|
||||
define i64 @bitcast_d_to_i(double %a) {
|
||||
; CHECK-LABEL: bitcast_d_to_i:
|
||||
; NONE-NOT: mov
|
||||
; HARD: vmov r0, r1, d0
|
||||
%1 = bitcast double %a to i64
|
||||
ret i64 %1
|
||||
}
|
||||
|
||||
define float @select_f(float %a, float %b, i1 %c) {
|
||||
; CHECK-LABEL: select_f:
|
||||
; NONE: tst.w r2, #1
|
||||
; NONE: moveq r0, r1
|
||||
; HARD: tst.w r0, #1
|
||||
; HARD: vmovne.f32 s1, s0
|
||||
; HARD: vmov.f32 s0, s1
|
||||
%1 = select i1 %c, float %a, float %b
|
||||
ret float %1
|
||||
}
|
||||
|
||||
define double @select_d(double %a, double %b, i1 %c) {
|
||||
; CHECK-LABEL: select_d:
|
||||
; NONE: ldr.w [[REG:r[0-9]+]], [sp]
|
||||
; NONE: ands [[REG]], [[REG]], #1
|
||||
; NONE: moveq r0, r2
|
||||
; NONE: moveq r1, r3
|
||||
; SP: ands r0, r0, #1
|
||||
; SP-DAG: vmov [[ALO:r[0-9]+]], [[AHI:r[0-9]+]], d0
|
||||
; SP-DAG: vmov [[BLO:r[0-9]+]], [[BHI:r[0-9]+]], d1
|
||||
; SP: itt ne
|
||||
; SP-DAG: movne [[BLO]], [[ALO]]
|
||||
; SP-DAG: movne [[BHI]], [[AHI]]
|
||||
; SP: vmov d0, [[BLO]], [[BHI]]
|
||||
; DP: tst.w r0, #1
|
||||
; DP: vmovne.f64 d1, d0
|
||||
; DP: vmov.f64 d0, d1
|
||||
%1 = select i1 %c, double %a, double %b
|
||||
ret double %1
|
||||
}
|
||||
Reference in New Issue
Block a user