aboutsummaryrefslogtreecommitdiff
path: root/src/bfloat16.adoc
blob: ba3e8bc86252459275dde1970211e5b29980cef3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
[[bf16]]
== "BF16" Extensions for for BFloat16-precision Floating-Point, Version 1.0

[[BF16_introduction]]
=== Introduction

When FP16 (officially called binary16) was first introduced by the IEEE-754 standard,
it was just an interchange format. It was intended as a space/bandwidth efficient
encoding that would be used to transfer information. This is in line with the Zfhmin
extension.

However, there were some applications (notably graphics) that found that the smaller
precision and dynamic range was sufficient for their space. So, FP16 started to see
some widespread adoption as an arithmetic format. This is in line with
the Zfh extension.

While it was not the intention of '754 to have FP16 be an arithmetic format, it is
supported by the standard. Even though the '754 committee recognized that FP16 was
gaining popularity, the committee decided to hold off on making it a basic format
in the 2019 release. This means that a '754 compliant implementation of binary
floating point, which needs to support at least one basic format, cannot support
only FP16 - it needs to support at least one of binary32, binary64, and binary128.

Experts working in machine learning noticed that FP16 was a much more compact way of
storing operands and often provided sufficient precision for them. However, they also
found that intermediate values were much better when accumulated into a higher precision.
The final computations were then typically converted back into the more compact FP16
encoding.  This approach has become very common in machine learning
(ML) inference where the weights and
activations are stored in FP16 encodings.  There was the added benefit that smaller
multiplication blocks could be created for the FP16's smaller number of significant bits. At this
point, widening multiply-accumulate instructions became much more common. Also, more
complicated dot product instructions started to show up including those that packed two
FP16 numbers in a 32-bit register, multiplied these by another pair of FP16 numbers in
another register, added these two products to an FP32 accumulate value in a 3rd register
and returned an FP32 result. 

Experts working in machine learning at Google who continued to work with FP32 values
noted that the least significant 16 bits of their mantissas were not always needed
for good results, even in training. They proposed a truncated version of FP32, which was
the 16 most significant bits of the FP32 encoding. This format was named BFloat16
(or BF16). The B in BF16, stands for Brain since it was initially introduced
by the Google Brain team. Not only did they find that the number of
significant bits in BF16 tended to be sufficient for their work (despite being fewer than
in FP16), but it was very easy for them to reuse their existing data; FP32 numbers could
be readily rounded to BF16 with a minimal amount of work. Furthermore, the even smaller
number of the BF16 significant bits enabled even smaller
multiplication blocks to be built. Similar
to FP16, BF16 multiply-accumulate widening and dot-product instructions started to
proliferate.

// include::riscv-bfloat16-audience.adoc[]
[[BF16_audience]]
=== Intended Audience
Floating-point arithmetic is a specialized subject, requiring people with many different
backgrounds to cooperate in its correct and efficient implementation.
Where possible, we have written this specification to be understandable by
all, though we recognize that the motivations and references to
algorithms or other specifications and standards may be unfamiliar to those
who are not domain experts.

This specification anticipates being read and acted on by various people
with different backgrounds.
We have tried to capture these backgrounds
here, with a brief explanation of what we expect them to know, and how
it relates to the specification.
We hope this aids people's understanding of which aspects of the specification
are particularly relevant to them, and which they may (safely!) ignore or
pass to a colleague.

Software developers::
These are the people we expect to write code using the instructions
in this specification.
They should understand the motivations for the
instructions we include, and be familiar with most of the algorithms
and outside standards to which we refer.

Computer architects::
We expect architects to have some basic floating-point background.
Furthermore, we expect architects to be able to examine our instructions
for implementation issues, understand how the instructions will be used
in context, and advise on how they best to fit the functionality.

Digital design engineers & micro-architects::
These are the people who will implement the specification inside a
core. Floating-point expertise is assumed as not all of the corner
cases are pointed out in the specification.

Verification engineers::
Responsible for ensuring the correct implementation of the extension
in hardware. These people are expected to have some floating-point
expertise so that they can identify and generate the interesting corner
cases --- include exceptions --- that are common in floating-point
architectures and implementations.


These are by no means the only people concerned with the specification,
but they are the ones we considered most while writing it.

[[BF16_format]]
=== Number Format

==== BF16 Operand Format

BF16 bits::
[wavedrom, , svg]
....
{reg:[
{bits: 7, name: 'frac'},
{bits: 8, name: 'expo'},
{bits: 1, name: 'S'},
]}
....

IEEE Compliance: While BF16 (also known as BFloat16) is not an IEEE-754 _standard_ format, it is a valid
floating-point format as defined by IEEE-754.
There are three parameters that specify a format: radix (b), number of digits in the significand (p),
and maximum exponent (emax).
For BF16 these values are:

[%autowidth]
.BF16 parameters
[cols = "2,1"]
|===
| Parameter | Value 
|radix (b)|2
|significand (p)|8
|emax|127
|===


[%autowidth]
.Obligatory Floating Point Format Table
[cols = "1,1,1,1,1,1,1,1"]
|===
|Format|Sign Bits|Expo Bits|fraction bits|padded 0s|encoding bits|expo max/bias|expo min

|FP16    |1| 5|10| 0|16|  15| -14
|BF16|1| 8| 7| 0|16| 127|-126
|TF32    |1| 8|10|13|32| 127|-126
|FP32    |1| 8|23| 0|32| 127|-126
|FP64    |1|11|52| 0|64|1023|-1022
|FP128   |1|15|112|0|128|16,383|-16,382
|===

==== BF16 Behavior

For these BF16 extensions, instruction behavior on BF16 operands is the same as for other floating-point
instructions in the RISC-V ISA. For easy reference, some of this behavior is repeated here.

===== Subnormal Numbers:
Floating-point values that are too small to be represented as normal numbers, but can still be expressed
by the format's smallest exponent value with a "0" integer bit and at least one "1" bit
in the trailing fractional bits are called subnormal numbers. Basically, the idea is there is
a trade off of precision to support _gradual underflow_.

All of the BF16 instructions in the extensions defined in this specification (i.e., Zfbfmin, Zvfbfmin
and Zvfbfwma) fully support subnormal numbers. That is, instructions are able to accept subnormal values as
inputs and they can produce subnormal results.


[NOTE]
====
Future floating-point extensions, including those that operate on BF16 values, may chose not to support subnormal numbers.
The comments about supporting subnormal BF16 values are limited to those instructions defined in this specification. 
====
 
=====  Infinities:
Infinities are used to represent values that are too large to be represented by the target format.
These are usually produced as a result of overflows (depending on the rounding mode), but can also
be provided as inputs. Infinities have a sign associated with them: there are positive infinities and negative infinities.

Infinities are important for keeping meaningless results from being operated upon.

===== NaNs

NaN stands for Not a Number. 

There are two types of NaNs: signalling (sNaN) and quiet (qNaN). No computational
instruction will ever produce an sNaN; These are only provided as input data. Operating on an sNaN will cause
an invalid operation exception. Operating on a Quiet NaN usually does not cause an exception.

QNaNs are provided as the result of an operation when it cannot be represented
as a number or infinity. For example, performing the square root of -1 will result in a qNaN because
there is no real number that can represent the result. NaNs can also be used as inputs.

NaNs include a sign bit, but the bit has no meaning.

NaNs are important for keeping meaningless results from being operated upon.

Except where otherwise explicitly stated, when the result of a floating-point operation is a qNaN, it
is the RISC-V canonical NaN. For BF16, the RISC-V canonical NaN corresponds to the pattern of _0x7fc0_ which
is the most significant 16 bits of the RISC-V single-precision canonical NaN.

===== Scalar NaN Boxing

RISC-V applies NaN boxing to scalar results and checks for NaN boxing when a floating-point operation
--- even a vector-scalar operation --- consumes a value from a scalar floating-point register.
If the value is properly NaN-boxed, its least significant bits are used as the operand, otherwise
it is treated as if it were the canonical QNaN.

NaN boxing is nothing more than putting the smaller encoding in the least significant bits of a register
and setting all of the more significant bits to “1”. This matches the encoding of a qNaN (although
not the canonical NaN) in the larger precision.

Nan-boxing never affects the value of the operand itself, it just changes the bits of the register that
are more significant than the operand's most significant bit.


=====  Rounding Modes:

As is the case with other floating-point instructions, 
the BF16 instructions support all 5 RISC-V Floating-point rounding modes.
These modes can be specified in the `rm` field of scalar instructions
as well as in the `frm` CSR  

[%autowidth]
.RISC-V Floating Point Rounding Modes
[cols = "1,1,1"]
|===
|Rounding Mode | Mnemonic | Meaning
|000 | RNE | Round to Nearest, ties to Even
|001 | RTZ | Round towards Zero
|010 | RDN | Round Down (towards −∞)
|011 | RUP | Round Up (towards +∞)
|100 | RMM | Round to Nearest, ties to Max Magnitude
|===
 
As with other scalar floating-point instructions, the rounding mode field
`rm` can also take on the 
`DYN` encoding, which indicates that the instruction uses the rounding
mode specified in the `frm` CSR.

[%autowidth]
.Additional encoding for the `rm` field of scalar instructions
[cols = "1,1,1"]
|===
|Rounding Mode | Mnemonic | Meaning
|111 | DYN | select dynamic rounding mode
|===

In practice, the default IEEE rounding mode (round to nearest, ties to even) is generally used for arithmetic.

===== Handling exceptions
RISC-V supports IEEE-defined default exception handling. BF16 is no exception.

Default exception handling, as defined by IEEE, is a simple and effective approach to producing results
in exceptional cases. For the coder to be able to see what has happened, and take further action if needed,
BF16 instructions set floating-point exception flags the same way as all other floating-point instructions
in RISC-V.

====== Underflow

The IEEE-defined underflow exception requires that a result be inexact and tiny, where tininess can be
detected before or after rounding. In RISC-V, tininess is detected after rounding.

It is important to note that the detection of tininess after rounding requires its own rounding
that is different from the final result rounding.  This tininess detection requires rounding as if the
exponent were unbounded.
This means that the input to the rounder is always a normal number.
This is different from the final result rounding where the input to the rounder is a subnormal number when
the value is too small to be represented as a normal number in the target format. 
The two different roundings can result in underflow being signalled for results that are rounded
back to the normal range.

As is defined in '754, under default exception handling, underflow is only signalled when the result is tiny
and inexact. In such a case, both the underflow and inexact flags are raised.

<<<

[[BF16_extensions]]
=== Extensions

The group of extensions introduced by the BF16 Instruction Set
Extensions is listed here.

Detection of individual BF16 extensions uses the
unified software-based RISC-V discovery method.

[NOTE]
====
At the time of writing, these discovery mechanisms are still a work in
progress.
====

The BF16 extensions defined in this specification (i.e., `Zfbfmin`,
`Zvfbfmin`, and `Zvfbfwma`) depend on the single-precision floating-point extension
`F`. Furthermore, the vector BF16 extensions (i.e.,`Zvfbfmin`, and
`Zvfbfwma`) depend on the `"V"` Vector Extension for Application
Processors or the `Zve32f` Vector Extension for Embedded Processors.

As stated later in this specification, 
there exists a dependency between the newly defined extensions:
`Zvfbfwma` depends on `Zfbfmin`
and `Zvfbfmin`.

This initial set of BF16 extensions provides very basic functionality
including  scalar and vector conversion between BF16 and
single-precision values, and vector widening multiply-accumulate
instructions.


// include::riscv-bfloat16-zfbfmin.adoc[]
[[zfbfmin, Zfbfmin]]
==== `Zfbfmin` - Scalar BF16 Converts

This extension provides the minimal set of instructions needed to enable scalar support
of the BF16 format. It enables BF16 as an interchange format as it provides conversion
between BF16 values and FP32 values. 

This extension requires the single-precision floating-point extension
`F`, and the `FLH`, `FSH`, `FMV.X.H`, and `FMV.H.X` instructions as
defined in the `Zfh` extension.

[NOTE]
====
While conversion instructions tend to include all supported formats, in these extensions we
only support conversion between BF16 and FP32 as we are targeting a special use case.
These extensions are intended to support the case where BF16 values are used as reduced
precision versions of FP32 values, where use of BF16 provides a two-fold advantage for
storage, bandwidth, and computation. In this use case, the BF16 values are typically 
multiplied by each other and accumulated into FP32 sums. 
These sums are typically converted to BF16
and then used as subsequent inputs. The operations on the BF16 values can be performed
on the CPU or a loosely coupled coprocessor.

Subsequent extensions might provide support for native BF16 arithmetic. Such extensions
could add additional conversion
instructions to allow all supported formats to be converted to and from BF16.  
====

[NOTE]
====
BF16 addition, subtraction, multiplication, division, and square-root operations can be
faithfully emulated by converting the BF16 operands to single-precision, performing the
operation using single-precision arithmetic, and then converting back to BF16. Performing
BF16 fused multiply-addition using this method can produce results that differ by 1-ulp 
on some inputs for the RNE and RMM rounding modes.


Conversions between BF16 and formats larger than FP32 can be
emulated.
Exact widening conversions from BF16 can be synthesized by first
converting to FP32 and then converting from FP32 to the target
precision. 
Conversions narrowing to BF16 can be synthesized by first
converting to FP32 through a series of halving steps and then
converting from FP32 to the target precision. 
As with the fused multiply-addition instruction described above,
this method of converting values to BF16 can be off by 1-ulp 
on some inputs for the RNE and RMM rounding modes.
====

[%autowidth]
[%header,cols="2,4"]
|===
|Mnemonic
|Instruction
|FCVT.BF16.S    | <<insns-fcvt.bf16.s>>
|FCVT.S.BF16    | <<insns-fcvt.s.bf16>>
|FLH            | 
|FSH            |
|FMV.H.X        |
|FMV.X.H        |
|===

// include::riscv-bfloat16-zvfbfmin.adoc[]
[[zvfbfmin,Zvfbfmin]]
==== `Zvfbfmin` - Vector BF16 Converts

This extension provides the minimal set of instructions needed to enable vector support of the BF16
format. It enables BF16 as an interchange format as it provides conversion between BF16 values
and FP32 values.

This extension requires either the
"V" extension or the `Zve32f` embedded vector extension.

[NOTE]
====
While conversion instructions tend to include all supported formats, in these extensions we
only support conversion between BF16 and FP32 as we are targeting a special use case.
These extensions are intended to support the case where BF16 values are used as reduced
precision versions of FP32 values, where use of BF16 provides a two-fold advantage for
storage, bandwidth, and computation. In this use case, the BF16 values are typically 
multiplied by each other and accumulated into FP32 sums. 
These sums are typically converted to BF16
and then used as subsequent inputs. The operations on the BF16 values can be performed
on the CPU or a loosely coupled coprocessor.

Subsequent extensions might provide support for native BF16 arithmetic. Such extensions
could add additional conversion
instructions to allow all supported formats to be converted to and from BF16.  
====

[NOTE]
====
BF16 addition, subtraction, multiplication, division, and square-root operations can be
faithfully emulated by converting the BF16 operands to single-precision, performing the
operation using single-precision arithmetic, and then converting back to BF16. Performing
BF16 fused multiply-addition using this method can produce results that differ by 1-ulp 
on some inputs for the RNE and RMM rounding modes.

Conversions between BF16 and formats larger than FP32 can be
faithfully emulated.
Exact widening conversions from BF16 can be synthesized by first
converting to FP32 and then converting from FP32 to the target
precision. Conversions narrowing to BF16 can be synthesized by first
converting to FP32 through a series of halving steps using
vector round-towards-odd narrowing conversion instructions
(_vfncvt.rod.f.f.w_). The final convert from FP32 to BF16 would use
the desired rounding mode.

====

[%autowidth]
[%header,cols="^2,4"]
|===
|Mnemonic
|Instruction
| vfncvtbf16.f.f.w   | <<insns-vfncvtbf16.f.f.w>>
| vfwcvtbf16.f.f.v   | <<insns-vfwcvtbf16.f.f.v>>
|===

// include::riscv-bfloat16-zvfbfwma.adoc[]
[[zvfbfwma,Zvfbfwma]]
==== `Zvfbfwma` - Vector BF16 widening mul-add

This extension provides
a vector widening BF16 mul-add instruction that accumulates into FP32. 

This extension requires the `Zvfbfmin` extension and the `Zfbfmin` extension.

[%autowidth]
[%header,cols="2,4"]
|===
|Mnemonic
|Instruction

|VFWMACCBF16 | <<insns-vfwmaccbf16>>
|===


[[BF16_insns, reftext="BF16 Instructions"]]
=== Instructions

// include::insns/fcvt_BF16_S.adoc[]
// <<<
[[insns-fcvt.bf16.s, Convert FP32 to BF16]]

==== fcvt.bf16.s

Synopsis::
Convert FP32 value to a BF16 value

Mnemonic::
fcvt.bf16.s rd, rs1

Encoding::
[wavedrom, , svg]
....
{reg:[
{bits: 7, name: '1010011', attr: ['OP-FP']},
{bits: 5, name: 'rd'},
{bits: 3, name: 'rm'},
{bits: 5, name: 'rs1'},
{bits: 5, name: '01000', attr: ['bf16.s']},
{bits: 2, name: '10', attr: ['h']},
{bits: 5, name: '01000', attr: 'fcvt'},
]}
....


[NOTE]
====
.Encoding
While the mnemonic of this instruction is consistent with that of the other RISC-V floating-point convert instructions,
a new encoding is used in bits 24:20.

`BF16.S` and `H` are used to signify that the source is FP32 and the destination is BF16.
====


Description::
Narrowing convert FP32 value to a BF16 value. Round according to the RM field.

This instruction is similar to other narrowing
floating-point-to-floating-point conversion instructions.


Exceptions:  Overflow, Underflow, Inexact, Invalid

Included in: <<zfbfmin>>

<<<
// include::insns/fcvt_S_BF16.adoc[]
// <<<
[[insns-fcvt.s.bf16, Convert BF16 to FP32]]
==== fcvt.s.bf16

Synopsis::
Convert BF16 value to an FP32 value

Mnemonic::
fcvt.s.bf16 rd, rs1

Encoding::
[wavedrom, , svg]
....
{reg:[
{bits: 7, name: '1010011', attr: ['OP-FP']},
{bits: 5, name: 'rd'},
{bits: 3, name: 'rm'},
{bits: 5, name: 'rs1'},
{bits: 5, name: '00110', attr: ['bf16']},
{bits: 2, name: '00', attr: ['s']},
{bits: 5, name: '01000', attr: 'fcvt'},
]}
....

[NOTE]
====
.Encoding
While the mnemonic of this instruction is consistent with that of the other RISC-V floating-point
convert instructions, a new encoding is
used in bits 24:20 to indicate that the source is BF16.
====


Description:: 
Converts a BF16 value to an FP32 value. The conversion is exact.

This instruction is similar to other widening
floating-point-to-floating-point conversion instructions.

[NOTE]
====
If the input is normal or infinity, the BF16 encoded value is shifted 
to the left by 16 places and the
least significant 16 bits are written with 0s.

The result is NaN-boxed by writing the most significant `FLEN`-32 bits with 1s.
====



Exceptions: Invalid

Included in: <<zfbfmin>>

<<<

// include::insns/vfncvtbf16_f_f_w.adoc[]
// <<<
[[insns-vfncvtbf16.f.f.w, Vector convert FP32 to BF16]]
==== vfncvtbf16.f.f.w

Synopsis::
Vector convert FP32 to BF16

Mnemonic::
vfncvtbf16.f.f.w vd, vs2, vm

Encoding::
[wavedrom, , svg]
....
{reg:[
{bits: 7, name: '1010111', attr:['OP-V']},
{bits: 5, name: 'vd'},
{bits: 3, name: '001', attr:['OPFVV']},
{bits: 5, name: '11101', attr:['vfncvtbf16']},
{bits: 5, name: 'vs2'},
{bits: 1, name: 'vm'},
{bits: 6, name: '010010', attr:['VFUNARY0']},
]}
....

Reserved Encodings::
* `SEW` is any value other than 16 

Arguments::

[%autowidth]
[%header,cols="4,2,2,2"]
|===
|Register
|Direction
|EEW
|Definition

| Vs2 | input  | 32  | FP32 Source
| Vd  | output | 16  | BF16 Result
|===



Description:: 
Narrowing convert from FP32 to BF16. Round according to the _frm_ register. 

This instruction is similar to `vfncvt.f.f.w` which converts a
floating-point value in a 2*SEW-width format into an SEW-width format.
However, here the SEW-width format is limited to BF16.

Exceptions:  Overflow, Underflow, Inexact, Invalid

Included in: <<zvfbfmin>>

<<<

// include::insns/vfwcvtbf16_f_f_v.adoc[]
// <<<
[[insns-vfwcvtbf16.f.f.v, Vector convert BF16 to FP32]]
==== vfwcvtbf16.f.f.v

Synopsis::
Vector convert BF16 to FP32

Mnemonic::
vfwcvtbf16.f.f.v vd, vs2, vm

Encoding::
[wavedrom, , svg]
....
{reg:[
{bits: 7, name: '1010111', attr:['OP-V']},
{bits: 5, name: 'vd'},
{bits: 3, name: '001', attr:['OPFVV']},
{bits: 5, name: '01101', attr:['vfwcvtbf16']},
{bits: 5, name: 'vs2'},
{bits: 1, name: 'vm'},
{bits: 6, name: '010010', attr:['VFUNARY0']},
]}
....

Reserved Encodings::
* `SEW` is any value other than 16 

Arguments::
[%autowidth]
[%header,cols="4,2,2,2"]
|===
|Register
|Direction
|EEW
|Definition

| Vs2 | input  | 16  | BF16 Source
| Vd  | output | 32  | FP32 Result
|===

Description:: 
Widening convert from BF16 to FP32. The conversion is exact.

This instruction is similar to `vfwcvt.f.f.v` which converts a
floating-point value in an SEW-width format into a 2*SEW-width format.
However, here the SEW-width format is limited to BF16.

[NOTE]
====
If the input is normal or infinity, the BF16 encoded value is shifted 
to the left by 16 places and the
least significant 16 bits are written with 0s.
====

Exceptions: Invalid

Included in: <<zvfbfmin>>

<<<

// include::insns/vfwmaccbf16.adoc[]
// <<<
[#insns-vfwmaccbf16, reftext="Vector BF16 widening multiply-accumulate"]
==== vfwmaccbf16 

Synopsis::
Vector BF16 widening multiply-accumulate

Mnemonic::
vfwmaccbf16.vv vd, vs1, vs2, vm +
vfwmaccbf16.vf vd, rs1, vs2, vm +

Encoding (Vector-Vector)::
[wavedrom, , svg]
....
{reg:[
{bits: 7, name: '1010111', attr:['OP-V']},
{bits: 5, name: 'vd'},
{bits: 3, name: '001', attr:['OPFVV']},
{bits: 5, name: 'vs1'},
{bits: 5, name: 'vs2'},
{bits: 1, name: 'vm'},
{bits: 6, name: '111011', attr:['vfwmaccbf16']},
]}
....

Encoding (Vector-Scalar)::
[wavedrom, , svg]
....
{reg:[
{bits: 7, name: '1010111', attr:['OP-V']},
{bits: 5, name: 'vd'},
{bits: 3, name: '101', attr:['OPFVF']},
{bits: 5, name: 'rs1'},
{bits: 5, name: 'vs2'},
{bits: 1, name: 'vm'},
{bits: 6, name: '111011', attr:['vfwmaccbf16']},
]}
....

Reserved Encodings::
* `SEW` is any value other than 16 

Arguments::
[%autowidth]
[%header,cols="4,2,2,2"]
|===
|Register
|Direction
|EEW
|Definition

| Vd      | input  | 32  | FP32 Accumulate
| Vs1/rs1 | input  | 16  | BF16 Source
| Vs2     | input  | 16  | BF16 Source
| Vd      | output | 32  | FP32 Result
|===

Description:: 

This instruction performs a widening fused multiply-accumulate
operation, where each pair of BF16 values are multiplied and their
unrounded product is added to the corresponding FP32 accumulate value.
The sum is rounded according to the _frm_ register.


In the vector-vector version, the BF16 elements are read from `vs1`
and `vs2` and FP32 accumulate value is read from `vd`. The FP32 result
is written to the destination register `vd`.

The vector-scalar version is similar, but instead of reading elements
from `vs1`, a scalar BF16 value is read from the FPU register `rs1`.  


Exceptions: Overflow, Underflow, Inexact, Invalid

Operation::

This `vfwmaccbf16.vv` instruction is equivalent to widening each of the BF16 inputs to
FP32 and then performing an FMACC as shown in the following
instruction sequence:

[source,asm]
--
vfwcvtbf16.f.f.v T1, vs1, vm
vfwcvtbf16.f.f.v T2, vs2, vm
vfmacc.vv        vd, T1, T2, vm
--

Likewise, `vfwmaccbf16.vf` is equivalent to the following instruction sequence:

[source,asm]
--
fcvt.s.bf16      T1, rs1
vfwcvtbf16.f.f.v T2, vs2, vm
vfmacc.vf        vd, T1, T2, vm
--

Included in: <<zvfbfwma>>


// include::../bibliography.adoc[ieee]
[bibliography]
=== Bibliography

// bibliography::[]

https://ieeexplore.ieee.org/document/8766229[754-2019 - IEEE Standard for Floating-Point Arithmetic] +
https://ieeexplore.ieee.org/document/4610935[754-2008 - IEEE Standard for Floating-Point Arithmetic]