Skip to content

Commit e4c3b03

Browse files
authored
[InstCombine] Fold tan(x) * cos(x) => sin(x) (#136319)
This patch enables folding `tan(x) * cos(x) -> sin(x)` under the `contract` flag. Fixes #34950.
1 parent 8fc20bf commit e4c3b03

File tree

2 files changed

+194
-0
lines changed

2 files changed

+194
-0
lines changed

llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1072,6 +1072,18 @@ Instruction *InstCombinerImpl::visitFMul(BinaryOperator &I) {
10721072
return Result;
10731073
}
10741074

1075+
// tan(X) * cos(X) -> sin(X)
1076+
if (I.hasAllowContract() &&
1077+
match(&I,
1078+
m_c_FMul(m_OneUse(m_Intrinsic<Intrinsic::tan>(m_Value(X))),
1079+
m_OneUse(m_Intrinsic<Intrinsic::cos>(m_Deferred(X)))))) {
1080+
auto *Sin = Builder.CreateUnaryIntrinsic(Intrinsic::sin, X, &I);
1081+
if (auto *Metadata = I.getMetadata(LLVMContext::MD_fpmath)) {
1082+
Sin->setMetadata(LLVMContext::MD_fpmath, Metadata);
1083+
}
1084+
return replaceInstUsesWith(I, Sin);
1085+
}
1086+
10751087
return nullptr;
10761088
}
10771089

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
2+
; RUN: opt -S -passes=instcombine < %s | FileCheck %s
3+
4+
define double @fmul_tan_cos(double %a) {
5+
; CHECK-LABEL: define double @fmul_tan_cos(
6+
; CHECK-SAME: double [[A:%.*]]) {
7+
; CHECK-NEXT: [[TAN:%.*]] = call double @llvm.tan.f64(double [[A]])
8+
; CHECK-NEXT: [[COS:%.*]] = call double @llvm.cos.f64(double [[A]])
9+
; CHECK-NEXT: [[RES:%.*]] = fmul double [[TAN]], [[COS]]
10+
; CHECK-NEXT: ret double [[RES]]
11+
;
12+
%tan = call double @llvm.tan.f64(double %a)
13+
%cos = call double @llvm.cos.f64(double %a)
14+
%res = fmul double %tan, %cos
15+
ret double %res
16+
}
17+
18+
define double @fmul_strict_tan_strict_cos_contract(double %a) {
19+
; CHECK-LABEL: define double @fmul_strict_tan_strict_cos_contract(
20+
; CHECK-SAME: double [[A:%.*]]) {
21+
; CHECK-NEXT: [[TAN:%.*]] = call double @llvm.tan.f64(double [[A]])
22+
; CHECK-NEXT: [[COS:%.*]] = call contract double @llvm.cos.f64(double [[A]])
23+
; CHECK-NEXT: [[RES:%.*]] = fmul double [[TAN]], [[COS]]
24+
; CHECK-NEXT: ret double [[RES]]
25+
;
26+
%tan = call double @llvm.tan.f64(double %a)
27+
%cos = call contract double @llvm.cos.f64(double %a)
28+
%res = fmul double %tan, %cos
29+
ret double %res
30+
}
31+
32+
define double @fmul_contract_tan_strict_cos_strict(double %a) {
33+
; CHECK-LABEL: define double @fmul_contract_tan_strict_cos_strict(
34+
; CHECK-SAME: double [[A:%.*]]) {
35+
; CHECK-NEXT: [[RES:%.*]] = call contract double @llvm.sin.f64(double [[A]])
36+
; CHECK-NEXT: ret double [[RES]]
37+
;
38+
%tan = call double @llvm.tan.f64(double %a)
39+
%cos = call double @llvm.cos.f64(double %a)
40+
%res = fmul contract double %tan, %cos
41+
ret double %res
42+
}
43+
44+
define double @fmul_contract_tan_contract_cos_strict(double %a) {
45+
; CHECK-LABEL: define double @fmul_contract_tan_contract_cos_strict(
46+
; CHECK-SAME: double [[A:%.*]]) {
47+
; CHECK-NEXT: [[RES:%.*]] = call contract double @llvm.sin.f64(double [[A]])
48+
; CHECK-NEXT: ret double [[RES]]
49+
;
50+
%tan = call contract double @llvm.tan.f64(double %a)
51+
%cos = call double @llvm.cos.f64(double %a)
52+
%res = fmul contract double %tan, %cos
53+
ret double %res
54+
}
55+
56+
define double @fmul_tan_cos_contract_multiple_uses(double %a) {
57+
; CHECK-LABEL: define double @fmul_tan_cos_contract_multiple_uses(
58+
; CHECK-SAME: double [[A:%.*]]) {
59+
; CHECK-NEXT: [[TAN:%.*]] = call contract double @llvm.tan.f64(double [[A]])
60+
; CHECK-NEXT: [[COS:%.*]] = call contract double @llvm.cos.f64(double [[A]])
61+
; CHECK-NEXT: [[RES:%.*]] = fmul contract double [[TAN]], [[COS]]
62+
; CHECK-NEXT: call void @use(double [[COS]])
63+
; CHECK-NEXT: ret double [[RES]]
64+
;
65+
%tan = call contract double @llvm.tan.f64(double %a)
66+
%cos = call contract double @llvm.cos.f64(double %a)
67+
%res = fmul contract double %tan, %cos
68+
call void @use(double %cos)
69+
ret double %res
70+
}
71+
72+
define double @fmul_tan_cos_contract(double %a) {
73+
; CHECK-LABEL: define double @fmul_tan_cos_contract(
74+
; CHECK-SAME: double [[A:%.*]]) {
75+
; CHECK-NEXT: [[RES:%.*]] = call contract double @llvm.sin.f64(double [[A]])
76+
; CHECK-NEXT: ret double [[RES]]
77+
;
78+
%tan = call contract double @llvm.tan.f64(double %a)
79+
%cos = call contract double @llvm.cos.f64(double %a)
80+
%res = fmul contract double %tan, %cos
81+
ret double %res
82+
}
83+
84+
define float @fmul_tanf_cosf_contract(float %a) {
85+
; CHECK-LABEL: define float @fmul_tanf_cosf_contract(
86+
; CHECK-SAME: float [[A:%.*]]) {
87+
; CHECK-NEXT: [[RES:%.*]] = call contract float @llvm.sin.f32(float [[A]])
88+
; CHECK-NEXT: ret float [[RES]]
89+
;
90+
%tan = call contract float @llvm.tan.f32(float %a)
91+
%cos = call contract float @llvm.cos.f32(float %a)
92+
%res = fmul contract float %tan, %cos
93+
ret float %res
94+
}
95+
96+
define fp128 @fmul_tanfp128_cosfp128_contract(fp128 %a) {
97+
; CHECK-LABEL: define fp128 @fmul_tanfp128_cosfp128_contract(
98+
; CHECK-SAME: fp128 [[A:%.*]]) {
99+
; CHECK-NEXT: [[RES:%.*]] = call contract fp128 @llvm.sin.f128(fp128 [[A]])
100+
; CHECK-NEXT: ret fp128 [[RES]]
101+
;
102+
%tan = call contract fp128 @llvm.tan.fp128(fp128 %a)
103+
%cos = call contract fp128 @llvm.cos.fp128(fp128 %a)
104+
%res = fmul contract fp128 %tan, %cos
105+
ret fp128 %res
106+
}
107+
108+
109+
define double @commutativity_cos_tan(double %a) {
110+
; CHECK-LABEL: define double @commutativity_cos_tan(
111+
; CHECK-SAME: double [[A:%.*]]) {
112+
; CHECK-NEXT: [[RES:%.*]] = call contract double @llvm.sin.f64(double [[A]])
113+
; CHECK-NEXT: ret double [[RES]]
114+
;
115+
%cos = call contract double @llvm.cos.f64(double %a)
116+
%tan = call contract double @llvm.tan.f64(double %a)
117+
%res = fmul contract double %cos, %tan
118+
ret double %res
119+
}
120+
121+
122+
define double @tan_cos_value_mismatch(double %a, double %b) {
123+
; CHECK-LABEL: define double @tan_cos_value_mismatch(
124+
; CHECK-SAME: double [[A:%.*]], double [[B:%.*]]) {
125+
; CHECK-NEXT: [[TAN:%.*]] = call contract double @llvm.tan.f64(double [[A]])
126+
; CHECK-NEXT: [[COS:%.*]] = call contract double @llvm.cos.f64(double [[B]])
127+
; CHECK-NEXT: [[RES:%.*]] = fmul contract double [[TAN]], [[COS]]
128+
; CHECK-NEXT: ret double [[RES]]
129+
;
130+
%tan = call contract double @llvm.tan.f64(double %a)
131+
%cos = call contract double @llvm.cos.f64(double %b)
132+
%res = fmul contract double %tan, %cos
133+
ret double %res
134+
}
135+
136+
137+
define <2 x double> @fmul_tan_cos_vector(<2 x double> %a) {
138+
; CHECK-LABEL: define <2 x double> @fmul_tan_cos_vector(
139+
; CHECK-SAME: <2 x double> [[A:%.*]]) {
140+
; CHECK-NEXT: [[RES:%.*]] = call contract <2 x double> @llvm.sin.v2f64(<2 x double> [[A]])
141+
; CHECK-NEXT: ret <2 x double> [[RES]]
142+
;
143+
%tan = call contract <2 x double> @llvm.tan.v2f64(<2 x double> %a)
144+
%cos = call contract <2 x double> @llvm.cos.v2f64(<2 x double> %a)
145+
%res = fmul contract <2 x double> %tan, %cos
146+
ret <2 x double> %res
147+
}
148+
149+
150+
define double @fmul_tan_cos_nnan_preservation(double %a) {
151+
; CHECK-LABEL: define double @fmul_tan_cos_nnan_preservation(
152+
; CHECK-SAME: double [[A:%.*]]) {
153+
; CHECK-NEXT: [[RES:%.*]] = call nnan contract double @llvm.sin.f64(double [[A]])
154+
; CHECK-NEXT: ret double [[RES]]
155+
;
156+
%tan = call contract double @llvm.tan.f64(double %a)
157+
%cos = call contract double @llvm.cos.f64(double %a)
158+
%res = fmul contract nnan double %tan, %cos
159+
ret double %res
160+
}
161+
162+
163+
define double @fmul_tan_cos_fpmath_metadata_preservation(double %a) {
164+
; CHECK-LABEL: define double @fmul_tan_cos_fpmath_metadata_preservation(
165+
; CHECK-SAME: double [[A:%.*]]) {
166+
; CHECK-NEXT: [[RES:%.*]] = call contract double @llvm.sin.f64(double [[A]]), !fpmath [[META0:![0-9]+]]
167+
; CHECK-NEXT: ret double [[RES]]
168+
;
169+
%tan = call contract double @llvm.tan.f64(double %a)
170+
%cos = call contract double @llvm.cos.f64(double %a)
171+
%res = fmul contract double %tan, %cos, !fpmath !0
172+
ret double %res
173+
}
174+
175+
declare void @use(double)
176+
177+
!0 = !{ float 2.5 }
178+
179+
180+
;.
181+
; CHECK: [[META0]] = !{float 2.500000e+00}
182+
;.

0 commit comments

Comments
 (0)