split out requirements analysis
[libreriscv.git] / ztrans_proposal.mdwn
1 # Zftrans - transcendental operations
2
3 See:
4
5 * <http://bugs.libre-riscv.org/show_bug.cgi?id=127>
6 * <https://www.khronos.org/registry/spir-v/specs/unified1/OpenCL.ExtendedInstructionSet.100.html>
7 * Discussion: <http://lists.libre-riscv.org/pipermail/libre-riscv-dev/2019-August/002342.html>
8 * [[rv_major_opcode_1010011]] for opcode listing.
9 * [[zfpacc_proposal]] for accuracy settings proposal
10
11 Extension subsets:
12
13 * **Zftrans**: standard transcendentals (best suited to 3D)
14 * **ZftransExt**: extra functions (useful, not generally needed for 3D,
15 can be synthesised using Ztrans)
16 * **Ztrigpi**: trig. xxx-pi sinpi cospi tanpi
17 * **Ztrignpi**: trig non-xxx-pi sin cos tan
18 * **Zarctrigpi**: arc-trig. a-xxx-pi: atan2pi asinpi acospi
19 * **Zarctrignpi**: arc-trig. non-a-xxx-pi: atan2, asin, acos
20 * **Zfhyp**: hyperbolic/inverse-hyperbolic. sinh, cosh, tanh, asinh,
21 acosh, atanh (can be synthesised - see below)
22 * **ZftransAdv**: much more complex to implement in hardware
23 * **Zfrsqrt**: Reciprocal square-root.
24
25 Minimum recommended requirements for 3D: Zftrans, Ztrigpi, Zarctrigpi,
26 Zarctrignpi
27
28 [[!toc levels=2]]
29
30 # TODO:
31
32 * Decision on accuracy, moved to [[zfpacc_proposal]]
33 <http://lists.libre-riscv.org/pipermail/libre-riscv-dev/2019-August/002355.html>
34 * Errors **MUST** be repeatable.
35 * How about four Platform Specifications? 3DUNIX, UNIX, 3DEmbedded and Embedded?
36 <http://lists.libre-riscv.org/pipermail/libre-riscv-dev/2019-August/002361.html>
37 Accuracy requirements for dual (triple) purpose implementations must
38 meet the higher standard.
39 * Reciprocal Square-root is in its own separate extension (Zfrsqrt) as
40 it is desirable on its own by other implementors. This to be evaluated.
41
42 # Requirements <a name="requirements"></a>
43
44 This proposal is designed to meet a wide range of extremely diverse needs,
45 allowing implementors from all of them to benefit from the tools and hardware
46 cost reductions associated with common standards adoption.
47
48 **There are *four* different, disparate platform's needs (two new)**:
49
50 * 3D Embedded Platform
51 * Embedded Platform
52 * 3D UNIX Platform
53 * UNIX Platform
54
55 **The use-cases are**:
56
57 * 3D GPUs
58 * Numerical Computation
59 * (Potentially) A.I. / Machine-learning (1)
60
61 (1) although approximations suffice in this field, making it more likely
62 to use a custom extension. High-end ML would inherently definitely
63 be excluded.
64
65 **The power and die-area requirements vary from**:
66
67 * Ultra-low-power (smartwatches where GPU power budgets are in milliwatts)
68 * Mobile-Embedded (good performance with high efficiency for battery life)
69 * Desktop Computing
70 * Server / HPC (2)
71
72 (2) Supercomputing is left out of the requirements as it is traditionally
73 covered by Supercomputer Vectorisation Standards (such as RVV).
74
75 **The software requirements are**:
76
77 * Full public integration into GNU math libraries (libm)
78 * Full public integration into well-known Numerical Computation systems (numpy)
79 * Full public integration into upstream GNU and LLVM Compiler toolchains
80 * Full public integration into Khronos OpenCL SPIR-V compatible Compilers
81 seeking public Certification and Endorsement from the Khronos Group
82 under their Trademarked Certification Programme.
83
84 **The "contra"-requirements are**:
85
86 * The requirements are **not** for the purposes of developing a full custom
87 proprietary GPU with proprietary firmware.
88 * A full custom proprietary GPU ASIC Manufacturer *may* benefit from
89 this proposal however the fact that they typically develop proprietary
90 software that is not shared with the rest of the community likely to
91 use this proposal means that they have completely different needs.
92 * This proposal is for *sharing* of effort in reducing development costs
93
94 # Requirements Analysis <a name="requirements_analysis"></a>
95
96 **Platforms**:
97
98 3D Embedded will require significantly less accuracy and will need to make
99 power budget and die area compromises that other platforms (including Embedded)
100 will not need to make.
101
102 3D UNIX Platform has to be performance-price-competitive: subtly-reduced
103 accuracy in FP32 is acceptable where, conversely, in the UNIX Platform,
104 IEEE754 compliance is a hard requirement that would compromise power
105 and efficiency on a 3D UNIX Platform.
106
107 Even in the Embedded platform, IEEE754 interoperability is beneficial,
108 where if it was a hard requirement the 3D Embedded platform would be severely
109 compromised in its ability to meet the demanding power budgets of that market.
110
111 Thus, learning from the lessons of
112 [SIMD considered harmful](https://www.sigarch.org/simd-instructions-considered-harmful/)
113 this proposal works in conjunction with the [[zfpacc_proposal]], so as
114 not to overburden the OP32 ISA space with extra "reduced-accuracy" opcodes.
115
116 **Use-cases**:
117
118 There really is little else in the way of suitable markets. 3D GPUs
119 have extremely competitive power-efficiency and power-budget requirements
120 that are completely at odds with the other market at the other end of
121 the spectrum: Numerical Computation.
122
123 Interoperability in Numerical Computation is absolutely critical: it implies
124 IEEE754 compliance. However full IEEE754 compliance automatically and
125 inherently penalises a GPU, where accuracy is simply just not necessary.
126
127 To meet the needs of both markets, the two new platforms have to be created,
128 and [[zfpacc_proposal]] is a critical dependency. Runtime selection of
129 FP accuracy allows an implementation to be "Hybrid" - cover UNIX IEEE754
130 compliance *and* 3D performance in a single ASIC.
131
132 **Power and die-area requirements**:
133
134 This is where the conflicts really start to hit home.
135
136 A "Numerical High performance only" proposal (suitable for Server / HPC
137 only) would customise and target the Extension based on a quantitative
138 analysis of the value of certain opcodes *for HPC only*. It would
139 conclude, reasonably and rationally, that it is worthwhile adding opcodes
140 to RVV as parallel Vector operations, and that further discussion of
141 the matter is pointless.
142
143 A "Proprietary GPU effort" (even one that was intended for publication
144 of its API through, for example, a public libre-licensed Vulkan SPIR-V
145 Compiler) would conclude, reasonably and rationally, that, likewise, the
146 opcodes were best suited to be added to RVV, and, further, that their
147 requirements conflict with the HPC world, due to the reduced accuracy.
148 This on the basis that the silicon die area required for IEEE754 is far
149 greater than that needed for reduced-accuracy, and thus their product would
150 be completely unacceptable in the market.
151
152 An "Embedded 3D" GPU has radically different performance, power
153 and die-area requirements (and may even target SoftCores in FPGA).
154 Sharing of the silicon to cover multi-function uses (CORDIC for example)
155 is absolutely essential in order to keep cost and power down, and high
156 performance simply is not. Multi-cycle FSMs instead of pipelines may
157 be considered acceptable, and so on. Subsets of functionality are
158 also essential.
159
160 An "Embedded Numerical" platform has requirements that are separate and
161 distinct from all of the above!
162
163 Mobile Computing needs (tablets, smartphones) again pull in a different
164 direction: high performance, reasonable accuracy, but efficiency is
165 critical. Screen sizes are not at the 4K range: they are within the
166 800x600 range at the low end (320x240 at the extreme budget end), and
167 only the high-performance smartphones and tablets provide 1080p (1920x1080).
168 With lower resolution, accuracy compromises are possible which the Desktop
169 market (4k and soon to be above) would find unacceptable.
170
171 Meeting these disparate markets may be achieved, again, through
172 [[zfpacc_proposal]], by subdividing into four platforms, yet, in addition
173 to that, subdividing the extension into subsets that best suit the different
174 market areas.
175
176 **Software requirements**:
177
178 A "custom" extension is developed in near-complete isolation from the
179 rest of the RISC-V Community. Cost savings to the Corporation are
180 large, with no direct beneficial feedback to (or impact on) the rest
181 of the RISC-V ecosystem.
182
183 However given that 3D revolves around Standards - DirectX, Vulkan, OpenGL,
184 OpenCL - users have much more influence than first appears. Compliance
185 with these standards is critical as the userbase (Games writers, scientific
186 applications) expects not to have to rewrite large codebases to conform
187 with non-standards-compliant hardware.
188
189 Therefore, compliance with public APIs is paramount, and compliance with
190 Trademarked Standards is critical. Any deviation from Trademarked Standards
191 means that an implementation may not be sold and also make a claim of being,
192 for example, "Vulkan compatible".
193
194 This in turn reinforces and makes a hard requirement a need for public
195 compliance with such standards, over-and-above what would otherwise be
196 set by a RISC-V Standards Development Process, including both the
197 software compliance and the knock-on implications that has for hardware.
198
199 **The "contra"-requirements are**:
200
201 * The requirements are **not** for the purposes of developing a full custom
202 proprietary GPU with proprietary firmware.
203 * A full custom proprietary GPU ASIC Manufacturer *may* benefit from
204 this proposal however the fact that they typically develop proprietary
205 software that is not shared with the rest of the community likely to
206 use this proposal means that they have completely different needs.
207
208 This proposal is for *sharing* of effort in reducing development costs,
209 and as such needs to be entirely public, transparent, and fully integrated
210 into public upstream libre-licensed libraries and toolchains.
211
212 *Overall this proposal is categorically and wholly unsuited to
213 relegation of "custom" status*.
214
215 # Proposed Opcodes vs Khronos OpenCL Opcodes <a name="khronos_equiv"></a>
216
217 This list shows the (direct) equivalence between proposed opcodes and
218 their Khronos OpenCL equivalents.
219
220 See
221 <https://www.khronos.org/registry/spir-v/specs/unified1/OpenCL.ExtendedInstructionSet.100.html>
222
223 Special FP16 opcodes are *not* being proposed, except by indirect / inherent
224 use of the "fmt" field that is already present in the RISC-V Specification.
225
226 "Native" opcodes are *not* being proposed: implementors will be expected
227 to use the (equivalent) proposed opcode covering the same function.
228
229 "Fast" opcodes are *not* being proposed, because the Khronos Specification
230 fast\_length, fast\_normalise and fast\_distance OpenCL opcodes require
231 vectors (or can be done as scalar operations using other RISC-V instructions).
232
233 The OpenCL FP32 opcodes are **direct** equivalents to the proposed opcodes.
234 Deviation from conformance with the Khronos Specification - including the
235 Khronos Specification accuracy requirements - is not an option.
236
237 [[!table data="""
238 Proposed opcode | OpenCL FP32 | OpenCL FP16 | OpenCL native | OpenCL fast |
239 FSIN | sin | half\_sin | native\_sin | NONE |
240 FCOS | cos | half\_cos | native\_cos | NONE |
241 FTAN | tan | half\_tan | native\_tan | NONE |
242 NONE (1) | sincos | NONE | NONE | NONE |
243 FASIN | asin | NONE | NONE | NONE |
244 FACOS | acos | NONE | NONE | NONE |
245 FATAN | atan | NONE | NONE | NONE |
246 FSINPI | sinpi | NONE | NONE | NONE |
247 FCOSPI | cospi | NONE | NONE | NONE |
248 FTANPI | tanpi | NONE | NONE | NONE |
249 FASINPI | asinpi | NONE | NONE | NONE |
250 FACOSPI | acospi | NONE | NONE | NONE |
251 FATANPI | atanpi | NONE | NONE | NONE |
252 FSINH | sinh | NONE | NONE | NONE |
253 FCOSH | cosh | NONE | NONE | NONE |
254 FTANH | tanh | NONE | NONE | NONE |
255 FASINH | asinh | NONE | NONE | NONE |
256 FACOSH | acosh | NONE | NONE | NONE |
257 FATANH | atanh | NONE | NONE | NONE |
258 FRSQRT | rsqrt | half\_rsqrt | native\_rsqrt | NONE |
259 FCBRT | cbrt | NONE | NONE | NONE |
260 FEXP2 | exp2 | half\_exp2 | native\_exp2 | NONE |
261 FLOG2 | log2 | half\_log2 | native\_log2 | NONE |
262 FEXPM1 | expm1 | NONE | NONE | NONE |
263 FLOG1P | log1p | NONE | NONE | NONE |
264 FEXP | exp | half\_exp | native\_exp | NONE |
265 FLOG | log | half\_log | native\_log | NONE |
266 FEXP10 | exp10 | half\_exp10 | native\_exp10 | NONE |
267 FLOG10 | log10 | half\_log10 | native\_log10 | NONE |
268 FATAN2 | atan2 | NONE | NONE | NONE |
269 FATAN2PI | atan2pi | NONE | NONE | NONE |
270 FPOW | pow | NONE | NONE | NONE |
271 FROOT | rootn | NONE | NONE | NONE |
272 FHYPOT | hypot | NONE | NONE | NONE |
273 FRECIP | NONE | half\_recip | native\_recip | NONE |
274 """]]
275
276 Note (1) FSINCOS is macro-op fused (see below).
277
278 # List of 2-arg opcodes
279
280 [[!table data="""
281 opcode | Description | pseudo-code | Extension |
282 FATAN2 | atan2 arc tangent | rd = atan2(rs2, rs1) | Zarctrignpi |
283 FATAN2PI | atan2 arc tangent / pi | rd = atan2(rs2, rs1) / pi | Zarctrigpi |
284 FPOW | x power of y | rd = pow(rs1, rs2) | ZftransAdv |
285 FROOT | x power 1/y | rd = pow(rs1, 1/rs2) | ZftransAdv |
286 FHYPOT | hypotenuse | rd = sqrt(rs1^2 + rs2^2) | Zftrans |
287 """]]
288
289 # List of 1-arg transcendental opcodes
290
291 [[!table data="""
292 opcode | Description | pseudo-code | Extension |
293 FRSQRT | Reciprocal Square-root | rd = sqrt(rs1) | Zfrsqrt |
294 FCBRT | Cube Root | rd = pow(rs1, 1.0 / 3) | Zftrans |
295 FRECIP | Reciprocal | rd = 1.0 / rs1 | Zftrans |
296 FEXP2 | power-of-2 | rd = pow(2, rs1) | Zftrans |
297 FLOG2 | log2 | rd = log(2. rs1) | Zftrans |
298 FEXPM1 | exponential minus 1 | rd = pow(e, rs1) - 1.0 | Zftrans |
299 FLOG1P | log plus 1 | rd = log(e, 1 + rs1) | Zftrans |
300 FEXP | exponential | rd = pow(e, rs1) | ZftransExt |
301 FLOG | natural log (base e) | rd = log(e, rs1) | ZftransExt |
302 FEXP10 | power-of-10 | rd = pow(10, rs1) | ZftransExt |
303 FLOG10 | log base 10 | rd = log(10, rs1) | ZftransExt |
304 """]]
305
306 # List of 1-arg trigonometric opcodes
307
308 [[!table data="""
309 opcode | Description | pseudo-code | Extension |
310 FSIN | sin (radians) | rd = sin(rs1) | Ztrignpi |
311 FCOS | cos (radians) | rd = cos(rs1) | Ztrignpi |
312 FTAN | tan (radians) | rd = tan(rs1) | Ztrignpi |
313 FASIN | arcsin (radians) | rd = asin(rs1) | Zarctrignpi |
314 FACOS | arccos (radians) | rd = acos(rs1) | Zarctrignpi |
315 FATAN (1) | arctan (radians) | rd = atan(rs1) | Zarctrignpi |
316 FSINPI | sin times pi | rd = sin(pi * rs1) | Ztrigpi |
317 FCOSPI | cos times pi | rd = cos(pi * rs1) | Ztrigpi |
318 FTANPI | tan times pi | rd = tan(pi * rs1) | Ztrigpi |
319 FASINPI | arcsin / pi | rd = asin(rs1) / pi | Zarctrigpi |
320 FACOSPI | arccos / pi | rd = acos(rs1) / pi | Zarctrigpi |
321 FATANPI (1) | arctan / pi | rd = atan(rs1) / pi | Zarctrigpi |
322 FSINH | hyperbolic sin (radians) | rd = sinh(rs1) | Zfhyp |
323 FCOSH | hyperbolic cos (radians) | rd = cosh(rs1) | Zfhyp |
324 FTANH | hyperbolic tan (radians) | rd = tanh(rs1) | Zfhyp |
325 FASINH | inverse hyperbolic sin | rd = asinh(rs1) | Zfhyp |
326 FACOSH | inverse hyperbolic cos | rd = acosh(rs1) | Zfhyp |
327 FATANH | inverse hyperbolic tan | rd = atanh(rs1) | Zfhyp |
328 """]]
329
330 Note (1): FATAN/FATANPI is a pseudo-op expanding to FATAN2/FATAN2PI (needs deciding)
331
332 # Synthesis, Pseudo-code ops and macro-ops
333
334 The pseudo-ops are best left up to the compiler rather than being actual
335 pseudo-ops, by allocating one scalar FP register for use as a constant
336 (loop invariant) set to "1.0" at the beginning of a function or other
337 suitable code block.
338
339 * FSINCOS - fused macro-op between FSIN and FCOS (issued in that order).
340 * FSINCOSPI - fused macro-op between FSINPI and FCOSPI (issued in that order).
341
342 FATANPI example pseudo-code:
343
344 lui t0, 0x3F800 // upper bits of f32 1.0
345 fmv.x.s ft0, t0
346 fatan2pi.s rd, rs1, ft0
347
348 Hyperbolic function example (obviates need for Zfhyp except for
349 high-performance or correctly-rounding):
350
351 ASINH( x ) = ln( x + SQRT(x**2+1))
352
353 # Reciprocal
354
355 Used to be an alias. Some imolementors may wish to implement divide as y times recip(x)
356
357 # To evaluate: should LOG be replaced with LOG1P (and EXP with EXPM1)?
358
359 RISC principle says "exclude LOG because it's covered by LOGP1 plus an ADD".
360 Research needed to ensure that implementors are not compromised by such
361 a decision
362 <http://lists.libre-riscv.org/pipermail/libre-riscv-dev/2019-August/002358.html>
363
364 > > correctly-rounded LOG will return different results than LOGP1 and ADD.
365 > > Likewise for EXP and EXPM1
366
367 > ok, they stay in as real opcodes, then.
368
369 # ATAN / ATAN2 commentary
370
371 Discussion starts here:
372 <http://lists.libre-riscv.org/pipermail/libre-riscv-dev/2019-August/002470.html>
373
374 from Mitch Alsup:
375
376 would like to point out that the general implementations of ATAN2 do a
377 bunch of special case checks and then simply call ATAN.
378
379 double ATAN2( double y, double x )
380 { // IEEE 754-2008 quality ATAN2
381
382 // deal with NANs
383 if( ISNAN( x ) ) return x;
384 if( ISNAN( y ) ) return y;
385
386 // deal with infinities
387 if( x == +∞ && |y|== +∞ ) return copysign( π/4, y );
388 if( x == +∞ ) return copysign( 0.0, y );
389 if( x == -∞ && |y|== +∞ ) return copysign( 3π/4, y );
390 if( x == -∞ ) return copysign( π, y );
391 if( |y|== +∞ ) return copysign( π/2, y );
392
393 // deal with signed zeros
394 if( x == 0.0 && y != 0.0 ) return copysign( π/2, y );
395 if( x >=+0.0 && y == 0.0 ) return copysign( 0.0, y );
396 if( x <=-0.0 && y == 0.0 ) return copysign( π, y );
397
398 // calculate ATAN2 textbook style
399 if( x > 0.0 ) return ATAN( |y / x| );
400 if( x < 0.0 ) return π - ATAN( |y / x| );
401 }
402
403
404 Yet the proposed encoding makes ATAN2 the primitive and has ATAN invent
405 a constant and then call/use ATAN2.
406
407 When one considers an implementation of ATAN, one must consider several
408 ranges of evaluation::
409
410 x [ -∞, -1.0]:: ATAN( x ) = -π/2 + ATAN( 1/x );
411 x (-1.0, +1.0]:: ATAN( x ) = + ATAN( x );
412 x [ 1.0, +∞]:: ATAN( x ) = +π/2 - ATAN( 1/x );
413
414 I should point out that the add/sub of π/2 can not lose significance
415 since the result of ATAN(1/x) is bounded 0..π/2
416
417 The bottom line is that I think you are choosing to make too many of
418 these into OpCodes, making the hardware function/calculation unit (and
419 sequencer) more complicated that necessary.
420
421 --------------------------------------------------------
422
423 I might suggest that if there were a way for a calculation to be performed
424 and the result of that calculation
425
426 chained to a subsequent calculation such that the precision of the
427 result-becomes-operand is wider than
428
429 what will fit in a register, then you can dramatically reduce the count
430 of instructions in this category while retaining
431
432 acceptable accuracy:
433
434 z = x / y
435
436 can be calculated as::
437
438 z = x * (1/y)
439
440 Where 1/y has about 26-to-32 bits of fraction. No, it's not IEEE 754-2008
441 accurate, but GPUs want speed and
442
443 1/y is fully pipelined (F32) while x/y cannot be (at reasonable area). It
444 is also not "that inaccurate" displaying 0.625-to-0.52 ULP.
445
446 Given that one has the ability to carry (and process) more fraction bits,
447 one can then do high precision multiplies of π or other transcendental
448 radixes.
449
450 And GPUs have been doing this almost since the dawn of 3D.
451
452 // calculate ATAN2 high performance style
453 // Note: at this point x != y
454 //
455 if( x > 0.0 )
456 {
457 if( y < 0.0 && |y| < |x| ) return - π/2 - ATAN( x / y );
458 if( y < 0.0 && |y| > |x| ) return + ATAN( y / x );
459 if( y > 0.0 && |y| < |x| ) return + ATAN( y / x );
460 if( y > 0.0 && |y| > |x| ) return + π/2 - ATAN( x / y );
461 }
462 if( x < 0.0 )
463 {
464 if( y < 0.0 && |y| < |x| ) return + π/2 + ATAN( x / y );
465 if( y < 0.0 && |y| > |x| ) return + π - ATAN( y / x );
466 if( y > 0.0 && |y| < |x| ) return + π - ATAN( y / x );
467 if( y > 0.0 && |y| > |x| ) return +3π/2 + ATAN( x / y );
468 }
469
470 This way the adds and subtracts from the constant are not in a precision
471 precarious position.