Skip to content

DAG: Fall back to separate sin and cos when softening sincos #147468

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions llvm/include/llvm/CodeGen/RuntimeLibcallUtil.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,14 @@ LLVM_ABI Libcall getLDEXP(EVT RetVT);
/// UNKNOWN_LIBCALL if there is none.
LLVM_ABI Libcall getFREXP(EVT RetVT);

/// Return the SIN_* value for the given types, or UNKNOWN_LIBCALL if there is
/// none.
LLVM_ABI Libcall getSIN(EVT RetVT);

/// Return the COS_* value for the given types, or UNKNOWN_LIBCALL if there is
/// none.
LLVM_ABI Libcall getCOS(EVT RetVT);

/// getSINCOS - Return the SINCOS_* value for the given types, or
/// UNKNOWN_LIBCALL if there is none.
LLVM_ABI Libcall getSINCOS(EVT RetVT);
Expand Down
43 changes: 36 additions & 7 deletions llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -794,7 +794,7 @@ SDValue DAGTypeLegalizer::SoftenFloatRes_FFREXP(SDNode *N) {
return ReturnVal;
}

SDValue DAGTypeLegalizer::SoftenFloatRes_UnaryWithTwoFPResults(
bool DAGTypeLegalizer::SoftenFloatRes_UnaryWithTwoFPResults(
SDNode *N, RTLIB::Libcall LC, std::optional<unsigned> CallRetResNo) {
assert(!N->isStrictFPOpcode() && "strictfp not implemented");
EVT VT = N->getValueType(0);
Expand All @@ -803,7 +803,7 @@ SDValue DAGTypeLegalizer::SoftenFloatRes_UnaryWithTwoFPResults(
"expected both return values to have the same type");

if (!TLI.getLibcallName(LC))
return SDValue();
return false;

EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), VT);

Expand Down Expand Up @@ -849,17 +849,46 @@ SDValue DAGTypeLegalizer::SoftenFloatRes_UnaryWithTwoFPResults(
SetSoftenedFloat(SDValue(N, ResNum), CreateStackLoad(SlackSlot));
}

return SDValue();
return true;
}

SDValue DAGTypeLegalizer::SoftenFloatRes_FSINCOS(SDNode *N) {
return SoftenFloatRes_UnaryWithTwoFPResults(
N, RTLIB::getSINCOS(N->getValueType(0)));
EVT VT = N->getValueType(0);
if (SoftenFloatRes_UnaryWithTwoFPResults(N, RTLIB::getSINCOS(VT)))
return SDValue();

// Fall back on softening the separate sin and cos calls if available.
RTLIB::Libcall SinLC = RTLIB::getSIN(VT);
RTLIB::Libcall CosLC = RTLIB::getCOS(VT);

SDValue SoftSin, SoftCos;
if (!TLI.getLibcallName(SinLC) || !TLI.getLibcallName(CosLC)) {
DAG.getContext()->emitError("do not know how to soften fsincos");

EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), VT);
SoftSin = SoftCos = DAG.getPOISON(NVT);
} else {
SoftSin = SoftenFloatRes_Unary(N, SinLC);
SoftCos = SoftenFloatRes_Unary(N, CosLC);
}

SetSoftenedFloat(SDValue(N, 0), SoftSin);
SetSoftenedFloat(SDValue(N, 1), SoftCos);
return SDValue();
}

SDValue DAGTypeLegalizer::SoftenFloatRes_FMODF(SDNode *N) {
return SoftenFloatRes_UnaryWithTwoFPResults(
N, RTLIB::getMODF(N->getValueType(0)), /*CallRetResNo=*/0);
EVT VT = N->getValueType(0);
if (SoftenFloatRes_UnaryWithTwoFPResults(N, RTLIB::getMODF(VT),
/*CallRetResNo=*/0))
return SDValue();

EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), VT);
DAG.getContext()->emitError("do not know how to soften fmodf");
SDValue Poison = DAG.getPOISON(NVT);
SetSoftenedFloat(SDValue(N, 0), Poison);
SetSoftenedFloat(SDValue(N, 1), Poison);
return SDValue();
}

SDValue DAGTypeLegalizer::SoftenFloatRes_FREM(SDNode *N) {
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -564,7 +564,7 @@ class LLVM_LIBRARY_VISIBILITY DAGTypeLegalizer {
// Convert Float Results to Integer.
void SoftenFloatResult(SDNode *N, unsigned ResNo);
SDValue SoftenFloatRes_Unary(SDNode *N, RTLIB::Libcall LC);
SDValue SoftenFloatRes_UnaryWithTwoFPResults(
bool SoftenFloatRes_UnaryWithTwoFPResults(
SDNode *N, RTLIB::Libcall LC, std::optional<unsigned> CallRetResNo = {});
SDValue SoftenFloatRes_Binary(SDNode *N, RTLIB::Libcall LC);
SDValue SoftenFloatRes_MERGE_VALUES(SDNode *N, unsigned ResNo);
Expand Down
8 changes: 8 additions & 0 deletions llvm/lib/CodeGen/TargetLoweringBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,14 @@ RTLIB::Libcall RTLIB::getFREXP(EVT RetVT) {
FREXP_PPCF128);
}

RTLIB::Libcall RTLIB::getSIN(EVT RetVT) {
return getFPLibCall(RetVT, SIN_F32, SIN_F64, SIN_F80, SIN_F128, SIN_PPCF128);
}

RTLIB::Libcall RTLIB::getCOS(EVT RetVT) {
return getFPLibCall(RetVT, COS_F32, COS_F64, COS_F80, COS_F128, COS_PPCF128);
}

RTLIB::Libcall RTLIB::getSINCOS(EVT RetVT) {
return getFPLibCall(RetVT, SINCOS_F32, SINCOS_F64, SINCOS_F80, SINCOS_F128,
SINCOS_PPCF128);
Expand Down
9 changes: 9 additions & 0 deletions llvm/test/CodeGen/AVR/sincos-soften-error.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
; RUN: not llc -mtriple=avr -filetype=null %s 2>&1 | FileCheck %s

; CHECK: error: do not know how to soften fsincos
define { double, double } @test_sincos_f64(double %a) #0 {
%result = call { double, double } @llvm.sincos.f64(double %a)
ret { double, double } %result
}

attributes #0 = { nounwind }
236 changes: 226 additions & 10 deletions llvm/test/CodeGen/WebAssembly/llvm.sincos.ll
Original file line number Diff line number Diff line change
Expand Up @@ -378,16 +378,232 @@ define { <2 x double>, <2 x double> } @test_sincos_v2f64(<2 x double> %a) #0 {
ret { <2 x double>, <2 x double> } %result
}

; ; FIXME: Asserts
; define { fp128, fp128 } @test_sincos_f128(fp128 %a) #0 {
; %result = call { fp128, fp128 } @llvm.sincos.f128(fp128 %a)
; ret { fp128, fp128 } %result
; }
define { fp128, fp128 } @test_sincos_f128(fp128 %a) #0 {
; WASM32-LABEL: test_sincos_f128:
; WASM32: .functype test_sincos_f128 (i32, i64, i64) -> ()
; WASM32-NEXT: .local i32
; WASM32-NEXT: # %bb.0:
; WASM32-NEXT: global.get __stack_pointer
; WASM32-NEXT: i32.const 32
; WASM32-NEXT: i32.sub
; WASM32-NEXT: local.tee 3
; WASM32-NEXT: global.set __stack_pointer
; WASM32-NEXT: local.get 3
; WASM32-NEXT: local.get 1
; WASM32-NEXT: local.get 2
; WASM32-NEXT: call cosl
; WASM32-NEXT: local.get 3
; WASM32-NEXT: i32.const 16
; WASM32-NEXT: i32.add
; WASM32-NEXT: local.get 1
; WASM32-NEXT: local.get 2
; WASM32-NEXT: call sinl
; WASM32-NEXT: local.get 0
; WASM32-NEXT: local.get 3
; WASM32-NEXT: i64.load 8
; WASM32-NEXT: i64.store 24
; WASM32-NEXT: local.get 0
; WASM32-NEXT: local.get 3
; WASM32-NEXT: i64.load 0
; WASM32-NEXT: i64.store 16
; WASM32-NEXT: local.get 0
; WASM32-NEXT: local.get 3
; WASM32-NEXT: i64.load 24
; WASM32-NEXT: i64.store 8
; WASM32-NEXT: local.get 0
; WASM32-NEXT: local.get 3
; WASM32-NEXT: i64.load 16
; WASM32-NEXT: i64.store 0
; WASM32-NEXT: local.get 3
; WASM32-NEXT: i32.const 32
; WASM32-NEXT: i32.add
; WASM32-NEXT: global.set __stack_pointer
; WASM32-NEXT: # fallthrough-return
;
; WASM64-LABEL: test_sincos_f128:
; WASM64: .functype test_sincos_f128 (i64, i64, i64) -> ()
; WASM64-NEXT: .local i64
; WASM64-NEXT: # %bb.0:
; WASM64-NEXT: global.get __stack_pointer
; WASM64-NEXT: i64.const 32
; WASM64-NEXT: i64.sub
; WASM64-NEXT: local.tee 3
; WASM64-NEXT: global.set __stack_pointer
; WASM64-NEXT: local.get 3
; WASM64-NEXT: local.get 1
; WASM64-NEXT: local.get 2
; WASM64-NEXT: call cosl
; WASM64-NEXT: local.get 3
; WASM64-NEXT: i64.const 16
; WASM64-NEXT: i64.add
; WASM64-NEXT: local.get 1
; WASM64-NEXT: local.get 2
; WASM64-NEXT: call sinl
; WASM64-NEXT: local.get 0
; WASM64-NEXT: local.get 3
; WASM64-NEXT: i64.load 8
; WASM64-NEXT: i64.store 24
; WASM64-NEXT: local.get 0
; WASM64-NEXT: local.get 3
; WASM64-NEXT: i64.load 0
; WASM64-NEXT: i64.store 16
; WASM64-NEXT: local.get 0
; WASM64-NEXT: local.get 3
; WASM64-NEXT: i64.load 24
; WASM64-NEXT: i64.store 8
; WASM64-NEXT: local.get 0
; WASM64-NEXT: local.get 3
; WASM64-NEXT: i64.load 16
; WASM64-NEXT: i64.store 0
; WASM64-NEXT: local.get 3
; WASM64-NEXT: i64.const 32
; WASM64-NEXT: i64.add
; WASM64-NEXT: global.set __stack_pointer
; WASM64-NEXT: # fallthrough-return
%result = call { fp128, fp128 } @llvm.sincos.f128(fp128 %a)
ret { fp128, fp128 } %result
}

; ; FIXME: Asserts
; define { <2 x fp128>, <2 x fp128> } @test_sincos_v2f128(<2 x fp128> %a) #0 {
; %result = call { <2 x fp128>, <2 x fp128> } @llvm.sincos.v2f128(<2 x fp128> %a)
; ret { <2 x fp128>, <2 x fp128> } %result
; }
define { <2 x fp128>, <2 x fp128> } @test_sincos_v2f128(<2 x fp128> %a) #0 {
; WASM32-LABEL: test_sincos_v2f128:
; WASM32: .functype test_sincos_v2f128 (i32, i64, i64, i64, i64) -> ()
; WASM32-NEXT: .local i32
; WASM32-NEXT: # %bb.0:
; WASM32-NEXT: global.get __stack_pointer
; WASM32-NEXT: i32.const 64
; WASM32-NEXT: i32.sub
; WASM32-NEXT: local.tee 5
; WASM32-NEXT: global.set __stack_pointer
; WASM32-NEXT: local.get 5
; WASM32-NEXT: i32.const 32
; WASM32-NEXT: i32.add
; WASM32-NEXT: local.get 3
; WASM32-NEXT: local.get 4
; WASM32-NEXT: call cosl
; WASM32-NEXT: local.get 5
; WASM32-NEXT: local.get 1
; WASM32-NEXT: local.get 2
; WASM32-NEXT: call cosl
; WASM32-NEXT: local.get 5
; WASM32-NEXT: i32.const 48
; WASM32-NEXT: i32.add
; WASM32-NEXT: local.get 3
; WASM32-NEXT: local.get 4
; WASM32-NEXT: call sinl
; WASM32-NEXT: local.get 5
; WASM32-NEXT: i32.const 16
; WASM32-NEXT: i32.add
; WASM32-NEXT: local.get 1
; WASM32-NEXT: local.get 2
; WASM32-NEXT: call sinl
; WASM32-NEXT: local.get 0
; WASM32-NEXT: local.get 5
; WASM32-NEXT: i64.load 40
; WASM32-NEXT: i64.store 56
; WASM32-NEXT: local.get 0
; WASM32-NEXT: local.get 5
; WASM32-NEXT: i64.load 32
; WASM32-NEXT: i64.store 48
; WASM32-NEXT: local.get 0
; WASM32-NEXT: local.get 5
; WASM32-NEXT: i64.load 8
; WASM32-NEXT: i64.store 40
; WASM32-NEXT: local.get 0
; WASM32-NEXT: local.get 5
; WASM32-NEXT: i64.load 0
; WASM32-NEXT: i64.store 32
; WASM32-NEXT: local.get 0
; WASM32-NEXT: local.get 5
; WASM32-NEXT: i64.load 56
; WASM32-NEXT: i64.store 24
; WASM32-NEXT: local.get 0
; WASM32-NEXT: local.get 5
; WASM32-NEXT: i64.load 48
; WASM32-NEXT: i64.store 16
; WASM32-NEXT: local.get 0
; WASM32-NEXT: local.get 5
; WASM32-NEXT: i64.load 24
; WASM32-NEXT: i64.store 8
; WASM32-NEXT: local.get 0
; WASM32-NEXT: local.get 5
; WASM32-NEXT: i64.load 16
; WASM32-NEXT: i64.store 0
; WASM32-NEXT: local.get 5
; WASM32-NEXT: i32.const 64
; WASM32-NEXT: i32.add
; WASM32-NEXT: global.set __stack_pointer
; WASM32-NEXT: # fallthrough-return
;
; WASM64-LABEL: test_sincos_v2f128:
; WASM64: .functype test_sincos_v2f128 (i64, i64, i64, i64, i64) -> ()
; WASM64-NEXT: .local i64
; WASM64-NEXT: # %bb.0:
; WASM64-NEXT: global.get __stack_pointer
; WASM64-NEXT: i64.const 64
; WASM64-NEXT: i64.sub
; WASM64-NEXT: local.tee 5
; WASM64-NEXT: global.set __stack_pointer
; WASM64-NEXT: local.get 5
; WASM64-NEXT: i64.const 32
; WASM64-NEXT: i64.add
; WASM64-NEXT: local.get 3
; WASM64-NEXT: local.get 4
; WASM64-NEXT: call cosl
; WASM64-NEXT: local.get 5
; WASM64-NEXT: local.get 1
; WASM64-NEXT: local.get 2
; WASM64-NEXT: call cosl
; WASM64-NEXT: local.get 5
; WASM64-NEXT: i64.const 48
; WASM64-NEXT: i64.add
; WASM64-NEXT: local.get 3
; WASM64-NEXT: local.get 4
; WASM64-NEXT: call sinl
; WASM64-NEXT: local.get 5
; WASM64-NEXT: i64.const 16
; WASM64-NEXT: i64.add
; WASM64-NEXT: local.get 1
; WASM64-NEXT: local.get 2
; WASM64-NEXT: call sinl
; WASM64-NEXT: local.get 0
; WASM64-NEXT: local.get 5
; WASM64-NEXT: i64.load 40
; WASM64-NEXT: i64.store 56
; WASM64-NEXT: local.get 0
; WASM64-NEXT: local.get 5
; WASM64-NEXT: i64.load 32
; WASM64-NEXT: i64.store 48
; WASM64-NEXT: local.get 0
; WASM64-NEXT: local.get 5
; WASM64-NEXT: i64.load 8
; WASM64-NEXT: i64.store 40
; WASM64-NEXT: local.get 0
; WASM64-NEXT: local.get 5
; WASM64-NEXT: i64.load 0
; WASM64-NEXT: i64.store 32
; WASM64-NEXT: local.get 0
; WASM64-NEXT: local.get 5
; WASM64-NEXT: i64.load 56
; WASM64-NEXT: i64.store 24
; WASM64-NEXT: local.get 0
; WASM64-NEXT: local.get 5
; WASM64-NEXT: i64.load 48
; WASM64-NEXT: i64.store 16
; WASM64-NEXT: local.get 0
; WASM64-NEXT: local.get 5
; WASM64-NEXT: i64.load 24
; WASM64-NEXT: i64.store 8
; WASM64-NEXT: local.get 0
; WASM64-NEXT: local.get 5
; WASM64-NEXT: i64.load 16
; WASM64-NEXT: i64.store 0
; WASM64-NEXT: local.get 5
; WASM64-NEXT: i64.const 64
; WASM64-NEXT: i64.add
; WASM64-NEXT: global.set __stack_pointer
; WASM64-NEXT: # fallthrough-return
%result = call { <2 x fp128>, <2 x fp128> } @llvm.sincos.v2f128(<2 x fp128> %a)
ret { <2 x fp128>, <2 x fp128> } %result
}

attributes #0 = { nounwind }
Loading