RuntimeLibcalls: Add sincos to the RISCV runtime libcall set - #215115
RuntimeLibcalls: Add sincos to the RISCV runtime libcall set#215115arsenm wants to merge 2 commits into
Conversation
Inspection of the glibc sources suggests this is generically available, with the target variance being for long double support. The set of library functions is a large historical mess I'm attempting to untangle. The traditional system had a large set of defaulted calls, but sincos was a case which was explicitly enabled, and I'm assuming riscv just never got around to adding it. It will be easier to reorganize the library functions if synthetic architectural glibc variance is eliminated. Co-authored-by: Claude (Claude-Opus-4.8) <noreply@anthropic.com>
|
@llvm/pr-subscribers-llvm-ir @llvm/pr-subscribers-backend-risc-v Author: Matt Arsenault (arsenm) ChangesInspection of the glibc sources suggests this is generically Co-authored-by: Claude (Claude-Opus-4.8) <noreply@anthropic.com> Full diff: https://github.com/llvm/llvm-project/pull/215115.diff 3 Files Affected:
diff --git a/llvm/include/llvm/IR/RuntimeLibcalls.td b/llvm/include/llvm/IR/RuntimeLibcalls.td
index b0d9663cca395..1b504c8de6add 100644
--- a/llvm/include/llvm/IR/RuntimeLibcalls.td
+++ b/llvm/include/llvm/IR/RuntimeLibcalls.td
@@ -3185,6 +3185,7 @@ def RISCVSystemLibrary
: SystemRuntimeLibrary<isRISCV,
(add DefaultRuntimeLibcallImpls,
exp10f, exp10, exp10l_f128,
+ LibmHasSinCosF32, LibmHasSinCosF64, LibmHasSinCosF128,
__riscv_flush_icache,
LibcallImpls<(add Int128RTLibcalls), isRISCV64>,
DefaultStackProtector,
diff --git a/llvm/test/CodeGen/RISCV/llvm.sincos.ll b/llvm/test/CodeGen/RISCV/llvm.sincos.ll
new file mode 100644
index 0000000000000..bb4935ba885ab
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/llvm.sincos.ll
@@ -0,0 +1,136 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -mtriple=riscv64-linux-gnu -mattr=+d < %s | FileCheck %s --check-prefix=RV64
+; RUN: llc -mtriple=riscv32-linux-gnu -mattr=+d < %s | FileCheck %s --check-prefix=RV32
+
+; Test the llvm.sincos intrinsic lowering to the sincos libcalls, which glibc
+; provides (sincosf/sincos/sincosl). RISCV long double is fp128, so f128 uses
+; sincosl.
+
+define { float, float } @test_sincos_f32(float %a) nounwind {
+; RV64-LABEL: test_sincos_f32:
+; RV64: # %bb.0:
+; RV64-NEXT: addi sp, sp, -16
+; RV64-NEXT: sd ra, 8(sp) # 8-byte Folded Spill
+; RV64-NEXT: addi a0, sp, 4
+; RV64-NEXT: mv a1, sp
+; RV64-NEXT: call sincosf
+; RV64-NEXT: flw fa0, 4(sp)
+; RV64-NEXT: flw fa1, 0(sp)
+; RV64-NEXT: ld ra, 8(sp) # 8-byte Folded Reload
+; RV64-NEXT: addi sp, sp, 16
+; RV64-NEXT: ret
+;
+; RV32-LABEL: test_sincos_f32:
+; RV32: # %bb.0:
+; RV32-NEXT: addi sp, sp, -16
+; RV32-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
+; RV32-NEXT: addi a0, sp, 8
+; RV32-NEXT: addi a1, sp, 4
+; RV32-NEXT: call sincosf
+; RV32-NEXT: flw fa0, 8(sp)
+; RV32-NEXT: flw fa1, 4(sp)
+; RV32-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
+; RV32-NEXT: addi sp, sp, 16
+; RV32-NEXT: ret
+ %result = call { float, float } @llvm.sincos.f32(float %a)
+ ret { float, float } %result
+}
+
+define { double, double } @test_sincos_f64(double %a) nounwind {
+; RV64-LABEL: test_sincos_f64:
+; RV64: # %bb.0:
+; RV64-NEXT: addi sp, sp, -32
+; RV64-NEXT: sd ra, 24(sp) # 8-byte Folded Spill
+; RV64-NEXT: addi a0, sp, 16
+; RV64-NEXT: addi a1, sp, 8
+; RV64-NEXT: call sincos
+; RV64-NEXT: fld fa0, 16(sp)
+; RV64-NEXT: fld fa1, 8(sp)
+; RV64-NEXT: ld ra, 24(sp) # 8-byte Folded Reload
+; RV64-NEXT: addi sp, sp, 32
+; RV64-NEXT: ret
+;
+; RV32-LABEL: test_sincos_f64:
+; RV32: # %bb.0:
+; RV32-NEXT: addi sp, sp, -32
+; RV32-NEXT: sw ra, 28(sp) # 4-byte Folded Spill
+; RV32-NEXT: addi a0, sp, 16
+; RV32-NEXT: addi a1, sp, 8
+; RV32-NEXT: call sincos
+; RV32-NEXT: fld fa0, 16(sp)
+; RV32-NEXT: fld fa1, 8(sp)
+; RV32-NEXT: lw ra, 28(sp) # 4-byte Folded Reload
+; RV32-NEXT: addi sp, sp, 32
+; RV32-NEXT: ret
+ %result = call { double, double } @llvm.sincos.f64(double %a)
+ ret { double, double } %result
+}
+
+define { fp128, fp128 } @test_sincos_f128(fp128 %a) nounwind {
+; RV64-LABEL: test_sincos_f128:
+; RV64: # %bb.0:
+; RV64-NEXT: addi sp, sp, -48
+; RV64-NEXT: sd ra, 40(sp) # 8-byte Folded Spill
+; RV64-NEXT: sd s0, 32(sp) # 8-byte Folded Spill
+; RV64-NEXT: mv a4, a2
+; RV64-NEXT: mv s0, a0
+; RV64-NEXT: addi a2, sp, 16
+; RV64-NEXT: mv a3, sp
+; RV64-NEXT: mv a0, a1
+; RV64-NEXT: mv a1, a4
+; RV64-NEXT: call sincosl
+; RV64-NEXT: ld a0, 16(sp)
+; RV64-NEXT: ld a1, 24(sp)
+; RV64-NEXT: ld a2, 0(sp)
+; RV64-NEXT: ld a3, 8(sp)
+; RV64-NEXT: sd a0, 0(s0)
+; RV64-NEXT: sd a1, 8(s0)
+; RV64-NEXT: sd a2, 16(s0)
+; RV64-NEXT: sd a3, 24(s0)
+; RV64-NEXT: ld ra, 40(sp) # 8-byte Folded Reload
+; RV64-NEXT: ld s0, 32(sp) # 8-byte Folded Reload
+; RV64-NEXT: addi sp, sp, 48
+; RV64-NEXT: ret
+;
+; RV32-LABEL: test_sincos_f128:
+; RV32: # %bb.0:
+; RV32-NEXT: addi sp, sp, -80
+; RV32-NEXT: sw ra, 76(sp) # 4-byte Folded Spill
+; RV32-NEXT: sw s0, 72(sp) # 4-byte Folded Spill
+; RV32-NEXT: lw a4, 0(a1)
+; RV32-NEXT: lw a5, 4(a1)
+; RV32-NEXT: lw a6, 8(a1)
+; RV32-NEXT: lw a7, 12(a1)
+; RV32-NEXT: mv s0, a0
+; RV32-NEXT: addi a0, sp, 24
+; RV32-NEXT: addi a1, sp, 8
+; RV32-NEXT: addi a2, sp, 56
+; RV32-NEXT: addi a3, sp, 40
+; RV32-NEXT: sw a4, 8(sp)
+; RV32-NEXT: sw a5, 12(sp)
+; RV32-NEXT: sw a6, 16(sp)
+; RV32-NEXT: sw a7, 20(sp)
+; RV32-NEXT: call sincosl
+; RV32-NEXT: lw a0, 40(sp)
+; RV32-NEXT: lw a1, 44(sp)
+; RV32-NEXT: lw a2, 48(sp)
+; RV32-NEXT: lw a3, 52(sp)
+; RV32-NEXT: lw a4, 56(sp)
+; RV32-NEXT: lw a5, 60(sp)
+; RV32-NEXT: lw a6, 64(sp)
+; RV32-NEXT: lw a7, 68(sp)
+; RV32-NEXT: sw a0, 16(s0)
+; RV32-NEXT: sw a1, 20(s0)
+; RV32-NEXT: sw a2, 24(s0)
+; RV32-NEXT: sw a3, 28(s0)
+; RV32-NEXT: sw a4, 0(s0)
+; RV32-NEXT: sw a5, 4(s0)
+; RV32-NEXT: sw a6, 8(s0)
+; RV32-NEXT: sw a7, 12(s0)
+; RV32-NEXT: lw ra, 76(sp) # 4-byte Folded Reload
+; RV32-NEXT: lw s0, 72(sp) # 4-byte Folded Reload
+; RV32-NEXT: addi sp, sp, 80
+; RV32-NEXT: ret
+ %result = call { fp128, fp128 } @llvm.sincos.f128(fp128 %a)
+ ret { fp128, fp128 } %result
+}
diff --git a/llvm/test/CodeGen/RISCV/sincos-expansion.ll b/llvm/test/CodeGen/RISCV/sincos-expansion.ll
index 6f37d67134cb3..606768a8e2f53 100644
--- a/llvm/test/CodeGen/RISCV/sincos-expansion.ll
+++ b/llvm/test/CodeGen/RISCV/sincos-expansion.ll
@@ -7,20 +7,16 @@
define float @test_sincos_f32(float %f) nounwind {
; CHECK-LABEL: test_sincos_f32:
; CHECK: # %bb.0:
-; CHECK-NEXT: addi sp, sp, -32
-; CHECK-NEXT: sd ra, 24(sp) # 8-byte Folded Spill
-; CHECK-NEXT: fsd fs0, 16(sp) # 8-byte Folded Spill
-; CHECK-NEXT: fsd fs1, 8(sp) # 8-byte Folded Spill
-; CHECK-NEXT: fmv.s fs0, fa0
-; CHECK-NEXT: call sinf
-; CHECK-NEXT: fmv.s fs1, fa0
-; CHECK-NEXT: fmv.s fa0, fs0
-; CHECK-NEXT: call cosf
-; CHECK-NEXT: fadd.s fa0, fs1, fa0
-; CHECK-NEXT: ld ra, 24(sp) # 8-byte Folded Reload
-; CHECK-NEXT: fld fs0, 16(sp) # 8-byte Folded Reload
-; CHECK-NEXT: fld fs1, 8(sp) # 8-byte Folded Reload
-; CHECK-NEXT: addi sp, sp, 32
+; CHECK-NEXT: addi sp, sp, -16
+; CHECK-NEXT: sd ra, 8(sp) # 8-byte Folded Spill
+; CHECK-NEXT: addi a0, sp, 4
+; CHECK-NEXT: mv a1, sp
+; CHECK-NEXT: call sincosf
+; CHECK-NEXT: flw fa5, 0(sp)
+; CHECK-NEXT: flw fa4, 4(sp)
+; CHECK-NEXT: fadd.s fa0, fa4, fa5
+; CHECK-NEXT: ld ra, 8(sp) # 8-byte Folded Reload
+; CHECK-NEXT: addi sp, sp, 16
; CHECK-NEXT: ret
%sin = call float @sinf(float %f) readnone
%cos = call float @cosf(float %f) readnone
@@ -57,17 +53,13 @@ define double @test_sincos_f64(double %f) nounwind {
; CHECK: # %bb.0:
; CHECK-NEXT: addi sp, sp, -32
; CHECK-NEXT: sd ra, 24(sp) # 8-byte Folded Spill
-; CHECK-NEXT: fsd fs0, 16(sp) # 8-byte Folded Spill
-; CHECK-NEXT: fsd fs1, 8(sp) # 8-byte Folded Spill
-; CHECK-NEXT: fmv.d fs0, fa0
-; CHECK-NEXT: call sin
-; CHECK-NEXT: fmv.d fs1, fa0
-; CHECK-NEXT: fmv.d fa0, fs0
-; CHECK-NEXT: call cos
-; CHECK-NEXT: fadd.d fa0, fs1, fa0
+; CHECK-NEXT: addi a0, sp, 16
+; CHECK-NEXT: addi a1, sp, 8
+; CHECK-NEXT: call sincos
+; CHECK-NEXT: fld fa5, 8(sp)
+; CHECK-NEXT: fld fa4, 16(sp)
+; CHECK-NEXT: fadd.d fa0, fa4, fa5
; CHECK-NEXT: ld ra, 24(sp) # 8-byte Folded Reload
-; CHECK-NEXT: fld fs0, 16(sp) # 8-byte Folded Reload
-; CHECK-NEXT: fld fs1, 8(sp) # 8-byte Folded Reload
; CHECK-NEXT: addi sp, sp, 32
; CHECK-NEXT: ret
%sin = call double @sin(double %f) readnone
|
| ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6 | ||
| ; RUN: llc -mtriple=riscv64-linux-gnu -mattr=+d -verify-machineinstrs -o - %s | FileCheck %s | ||
|
|
||
| ; Test adapted from AArch64. Demonstrates the cases where sin and cos libcalls |
There was a problem hiding this comment.
The purpose and behaviour of this test seem a bit puzzling to me. The test suggests that it is meant to demonstrate the cases where sin+cos are combined into sincos, but prior to this change, that didn't happen for any cases. And with this change, the 32/64 bit versions are combined when the readnone attribute is present, but this doesn't happen for the 128 bit version. Why?
There was a problem hiding this comment.
f128 / long double are more broken than not across most targets. I'm separately working on fixing that (#214944 is part)
| : SystemRuntimeLibrary<isRISCV, | ||
| (add DefaultRuntimeLibcallImpls, | ||
| exp10f, exp10, exp10l_f128, | ||
| LibmHasSinCosF32, LibmHasSinCosF64, LibmHasSinCosF128, |
There was a problem hiding this comment.
Just out of curiosity - if these are generally available on all targets, why not just get rid of the predicates?
There was a problem hiding this comment.
It's available on all targets, with glibc not any libc

Inspection of the glibc sources suggests this is generically
available, with the target variance being for long double support.
The set of library functions is a large historical mess I'm attempting
to untangle. The traditional system had a large set of defaulted calls,
but sincos was a case which was explicitly enabled, and I'm assuming
riscv just never got around to adding it. It will be easier to
reorganize the library functions if synthetic architectural glibc
variance is eliminated.
Co-authored-by: Claude (Claude-Opus-4.8) noreply@anthropic.com