Skip to content

Commit

Permalink
[RISCV][MC] Add support for experimental Zfbfmin extension
Browse files Browse the repository at this point in the history
Provides MC layer support for Zfbfmin: scalar BF16 conversions.

As documented, this extension includes FLH, FSH, FMV.H.X, and FMH.X.H as
defined in Zfh/Zfhmin, but doesn't require either extension.

No Zfbfinxmin has been defined (though you would expect one in the
future, for symmetry with Zfhinxmin). See issue
riscv/riscv-bfloat16#27.

Differential Revision: https://reviews.llvm.org/D147610
  • Loading branch information
asb committed May 19, 2023
1 parent b6bf28f commit 35ff5eb
Show file tree
Hide file tree
Showing 15 changed files with 156 additions and 6 deletions.
9 changes: 9 additions & 0 deletions clang/test/Preprocessor/riscv-target-features.c
Expand Up @@ -67,6 +67,7 @@
// CHECK-NOT: __riscv_zicond {{.*$}}
// CHECK-NOT: __riscv_smaia {{.*$}}
// CHECK-NOT: __riscv_ssaia {{.*$}}
// CHECK-NOT: __riscv_zfbfmin {{.*$}}

// RUN: %clang -target riscv32-unknown-linux-gnu -march=rv32i -x c -E -dM %s \
// RUN: -o - | FileCheck %s
Expand Down Expand Up @@ -674,3 +675,11 @@
// RUN: -march=rv64issaia1p0 -x c -E -dM %s \
// RUN: -o - | FileCheck --check-prefix=CHECK-SSAIA-EXT %s
// CHECK-SSAIA-EXT: __riscv_ssaia 1000000{{$}}

// RUN: %clang -target riscv32 -menable-experimental-extensions \
// RUN: -march=rv32izfbfmin0p6 -x c -E -dM %s \
// RUN: -o - | FileCheck --check-prefix=CHECK-ZFBFMIN-EXT %s
// RUN: %clang -target riscv64 -menable-experimental-extensions \
// RUN: -march=rv64izfbfmin0p6 -x c -E -dM %s \
// RUN: -o - | FileCheck --check-prefix=CHECK-ZFBFMIN-EXT %s
// CHECK-ZFBFMIN-EXT: __riscv_zfbfmin 6000{{$}}
3 changes: 3 additions & 0 deletions llvm/docs/RISCVUsage.rst
Expand Up @@ -204,6 +204,9 @@ The primary goal of experimental support is to assist in the process of ratifica
``experimental-zfa``
LLVM implements the `0.2 draft specification <https://github.com/riscv/riscv-isa-manual/releases/download/draft-20230131-c0b298a/zfa-20230414.pdf>`__.

``experimental-zfbfmin``
LLVM implements assembler support for the `0.6 draft specification <https://github.com/riscv/riscv-bfloat16/releases/tag/main>`_.

``experimental-zicond``
LLVM implements the `1.0-rc1 draft specification <https://github.com/riscv/riscv-zicond/releases/tag/v1.0-rc1>`__.

Expand Down
2 changes: 2 additions & 0 deletions llvm/docs/ReleaseNotes.rst
Expand Up @@ -180,6 +180,8 @@ Changes to the RISC-V Backend
* Add sifive-x280 processor.
* Zve32f is no longer allowed with Zfinx. Zve64d is no longer allowed with
Zdinx.
* Assembly support was added for the experimental Zfbfmin (scalar BF16
conversions) extension.

Changes to the WebAssembly Backend
----------------------------------
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Support/RISCVISAInfo.cpp
Expand Up @@ -147,6 +147,7 @@ static const RISCVSupportedExtension SupportedExperimentalExtensions[] = {
{"zcmp", RISCVExtensionVersion{1, 0}},
{"zcmt", RISCVExtensionVersion{1, 0}},
{"zfa", RISCVExtensionVersion{0, 2}},
{"zfbfmin", RISCVExtensionVersion{0, 6}},
{"zicond", RISCVExtensionVersion{1, 0}},
{"zvfh", RISCVExtensionVersion{0, 1}},
{"ztso", RISCVExtensionVersion{0, 1}},
Expand Down
15 changes: 15 additions & 0 deletions llvm/lib/Target/RISCV/RISCVFeatures.td
Expand Up @@ -611,6 +611,21 @@ def FeatureStdExtSsaia
"excluding the machine-level CSRs and behavior not "
"directly visible to supervisor level.)", []>;

def FeatureStdExtZfbfmin
: SubtargetFeature<"experimental-zfbfmin", "HasStdExtZfbfmin", "true",
"'Zfbfmin' (Scalar BF16 Converts)",
[FeatureStdExtF]>;
def HasStdExtZfbfmin : Predicate<"Subtarget->hasStdExtZfbfmin()">,
AssemblerPredicate<(all_of FeatureStdExtZfbfmin),
"'Zfbfmin' (Scalar BF16 Converts)">;

def HasHalfFPLoadStoreMove
: Predicate<"Subtarget->hasHalfFPLoadStoreMove()">,
AssemblerPredicate<(any_of FeatureStdExtZfh, FeatureStdExtZfhmin, FeatureStdExtZfbfmin),
"'Zfh' (Half-Precision Floating-Point) or "
"'Zfhmin' (Half-Precision Floating-Point Minimal) or "
"'Zfbfmin' (Scalar BF16 Converts)">;

//===----------------------------------------------------------------------===//
// Vendor extensions
//===----------------------------------------------------------------------===//
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Target/RISCV/RISCVInstrInfo.td
Expand Up @@ -1904,6 +1904,7 @@ include "RISCVInstrInfoZc.td"
include "RISCVInstrInfoZk.td"
include "RISCVInstrInfoV.td"
include "RISCVInstrInfoZfa.td"
include "RISCVInstrInfoZfbfmin.td"
include "RISCVInstrInfoZfh.td"
include "RISCVInstrInfoZicbo.td"
include "RISCVInstrInfoZicond.td"
Expand Down
25 changes: 25 additions & 0 deletions llvm/lib/Target/RISCV/RISCVInstrInfoZfbfmin.td
@@ -0,0 +1,25 @@
//===-- RISCVInstrInfoZfbfmin.td - 'Zfbfmin' instructions --*- tablegen -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file describes the RISC-V instructions from the standard 'Zfbfmin'
// extension, providing scalar conversion instructions for BFloat16.
// This version is still experimental as the 'Zfbfmin' extension hasn't been
// ratified yet.
//
//===----------------------------------------------------------------------===//

//===----------------------------------------------------------------------===//
// Instructions
//===----------------------------------------------------------------------===//

let Predicates = [HasStdExtZfbfmin] in {
def FCVT_BF16_S : FPUnaryOp_r_frm<0b0100010, 0b01000, FPR16, FPR32, "fcvt.bf16.s">,
Sched<[WriteFCvtF32ToF16, ReadFCvtF32ToF16]>;
def FCVT_S_BF16 : FPUnaryOp_r_frm<0b0100000, 0b00110, FPR32, FPR16, "fcvt.s.bf16">,
Sched<[WriteFCvtF32ToF16, ReadFCvtF32ToF16]>;
} // Predicates = [HasStdExtZfbfmin]
8 changes: 4 additions & 4 deletions llvm/lib/Target/RISCV/RISCVInstrInfoZfh.td
Expand Up @@ -90,14 +90,14 @@ defvar HDINXmin = [HDmin, HD_INXmin, HD_INX32min];
// Instructions
//===----------------------------------------------------------------------===//

let Predicates = [HasStdExtZfhOrZfhmin] in {
let Predicates = [HasHalfFPLoadStoreMove] in {
def FLH : FPLoad_r<0b001, "flh", FPR16, WriteFLD16>;

// Operands for stores are in the order srcreg, base, offset rather than
// reflecting the order these fields are specified in the instruction
// encoding.
def FSH : FPStore_r<0b001, "fsh", FPR16, WriteFST16>;
} // Predicates = [HasStdExtZfhOrZfhmin]
} // Predicates = [HasHalfFPLoadStoreMove]

let SchedRW = [WriteFMA16, ReadFMA16, ReadFMA16, ReadFMA16] in {
defm FMADD_H : FPFMA_rrr_frm_m<OPC_MADD, 0b10, "fmadd.h", HINX>;
Expand Down Expand Up @@ -151,15 +151,15 @@ defm FCVT_H_S : FPUnaryOp_r_frm_m<0b0100010, 0b00000, HFINXmin, "fcvt.h.s">,
defm FCVT_S_H : FPUnaryOp_r_m<0b0100000, 0b00010, 0b000, FHINXmin, "fcvt.s.h">,
Sched<[WriteFCvtF16ToF32, ReadFCvtF16ToF32]>;

let Predicates = [HasStdExtZfhOrZfhmin] in {
let Predicates = [HasHalfFPLoadStoreMove] in {
let mayRaiseFPException = 0, IsSignExtendingOpW = 1 in
def FMV_X_H : FPUnaryOp_r<0b1110010, 0b00000, 0b000, GPR, FPR16, "fmv.x.h">,
Sched<[WriteFMovF16ToI16, ReadFMovF16ToI16]>;

let mayRaiseFPException = 0 in
def FMV_H_X : FPUnaryOp_r<0b1111010, 0b00000, 0b000, FPR16, GPR, "fmv.h.x">,
Sched<[WriteFMovI16ToF16, ReadFMovI16ToF16]>;
} // Predicates = [HasStdExtZfhOrZfhmin]
} // Predicates = [HasHalfFPLoadStoreMove]

let SchedRW = [WriteFCmp16, ReadFCmp16, ReadFCmp16] in {
defm FEQ_H : FPCmp_rr_m<0b1010010, 0b010, "feq.h", HINX, /*Commutable*/1>;
Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/Target/RISCV/RISCVSubtarget.h
Expand Up @@ -123,6 +123,9 @@ class RISCVSubtarget : public RISCVGenSubtargetInfo {
bool hasStdExtZfhOrZfhminOrZhinxOrZhinxmin() const {
return hasStdExtZfhOrZfhmin() || hasStdExtZhinxOrZhinxmin();
}
bool hasHalfFPLoadStoreMove() const {
return HasStdExtZfh || HasStdExtZfhmin || HasStdExtZfbfmin;
}
bool is64Bit() const { return IsRV64; }
MVT getXLenVT() const { return XLenVT; }
unsigned getXLen() const { return XLen; }
Expand Down
4 changes: 4 additions & 0 deletions llvm/test/CodeGen/RISCV/attributes.ll
Expand Up @@ -74,6 +74,7 @@
; RUN: llc -mtriple=riscv32 -mattr=+experimental-zicond %s -o - | FileCheck --check-prefix=RV32ZICOND %s
; RUN: llc -mtriple=riscv32 -mattr=+experimental-smaia %s -o - | FileCheck --check-prefixes=CHECK,RV32SMAIA %s
; RUN: llc -mtriple=riscv32 -mattr=+experimental-ssaia %s -o - | FileCheck --check-prefixes=CHECK,RV32SSAIA %s
; RUN: llc -mtriple=riscv32 -mattr=+experimental-zfbfmin %s -o - | FileCheck --check-prefixes=CHECK,RV32ZFBFMIN %s

; RUN: llc -mtriple=riscv64 %s -o - | FileCheck %s
; RUN: llc -mtriple=riscv64 -mattr=+m %s -o - | FileCheck --check-prefixes=CHECK,RV64M %s
Expand Down Expand Up @@ -155,6 +156,7 @@
; RUN: llc -mtriple=riscv64 -mattr=+experimental-zicond %s -o - | FileCheck --check-prefix=RV64ZICOND %s
; RUN: llc -mtriple=riscv64 -mattr=+experimental-smaia %s -o - | FileCheck --check-prefixes=CHECK,RV64SMAIA %s
; RUN: llc -mtriple=riscv64 -mattr=+experimental-ssaia %s -o - | FileCheck --check-prefixes=CHECK,RV64SSAIA %s
; RUN: llc -mtriple=riscv64 -mattr=+experimental-zfbfmin %s -o - | FileCheck --check-prefixes=CHECK,RV64ZFBFMIN %s

; CHECK: .attribute 4, 16

Expand Down Expand Up @@ -231,6 +233,7 @@
; RV32ZICOND: .attribute 5, "rv32i2p1_zicond1p0"
; RV32SMAIA: .attribute 5, "rv32i2p1_smaia1p0"
; RV32SSAIA: .attribute 5, "rv32i2p1_ssaia1p0"
; RV32ZFBFMIN: .attribute 5, "rv32i2p1_f2p2_zicsr2p0_zfbfmin0p6"

; RV64M: .attribute 5, "rv64i2p1_m2p0"
; RV64ZMMUL: .attribute 5, "rv64i2p1_zmmul1p0"
Expand Down Expand Up @@ -311,6 +314,7 @@
; RV64ZICOND: .attribute 5, "rv64i2p1_zicond1p0"
; RV64SMAIA: .attribute 5, "rv64i2p1_smaia1p0"
; RV64SSAIA: .attribute 5, "rv64i2p1_ssaia1p0"
; RV64ZFBFMIN: .attribute 5, "rv64i2p1_f2p2_zicsr2p0_zfbfmin0p6"

define i32 @addi(i32 %a) {
%1 = add i32 %a, 1
Expand Down
3 changes: 3 additions & 0 deletions llvm/test/MC/RISCV/attribute-arch.s
Expand Up @@ -263,3 +263,6 @@

.attribute arch, "rv32i_ssaia1p0"
# CHECK: attribute 5, "rv32i2p1_ssaia1p0"

.attribute arch, "rv32if_zfbfmin0p6"
# CHECK: .attribute 5, "rv32i2p1_f2p2_zicsr2p0_zfbfmin0p6"
28 changes: 28 additions & 0 deletions llvm/test/MC/RISCV/rv32zfbfmin-invalid.s
@@ -0,0 +1,28 @@
# RUN: not llvm-mc -triple riscv32 -mattr=+experimental-zfbfmin,+d < %s 2>&1 | \
# RUN: FileCheck %s
# RUN: not llvm-mc -triple riscv64 -mattr=+experimental-zfbfmin,+d < %s 2>&1 | \
# RUN: FileCheck %s

# Out of range immediates
## simm12
flh ft1, -2049(a0) # CHECK: :[[@LINE]]:10: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo modifier or an integer in the range [-2048, 2047]
fsh ft2, 2048(a1) # CHECK: :[[@LINE]]:10: error: operand must be a symbol with %lo/%pcrel_lo/%tprel_lo modifier or an integer in the range [-2048, 2047]

# Memory operand not formatted correctly
flh ft1, a0, -200 # CHECK: :[[@LINE]]:14: error: invalid operand for instruction

# Invalid register names
flh ft15, 100(a0) # CHECK: :[[@LINE]]:5: error: invalid operand for instruction
flh ft1, 100(a10) # CHECK: :[[@LINE]]:14: error: expected register

# Integer registers where FP regs are expected
fmv.x.h fs7, a2 # CHECK: :[[@LINE]]:9: error: invalid operand for instruction

# FP registers where integer regs are expected
fmv.h.x a8, ft2 # CHECK: :[[@LINE]]:9: error: invalid operand for instruction

# Attempting to use fcvt instructions from zfhmin
fcvt.s.h fa0, ft0 # CHECK: [[@LINE]]:1: error: instruction requires the following: 'Zfh' (Half-Precision Floating-Point) or 'Zfhmin' (Half-Precision Floating-Point Minimal)
fcvt.h.s ft2, fa2 # CHECK: [[@LINE]]:1: error: instruction requires the following: 'Zfh' (Half-Precision Floating-Point) or 'Zfhmin' (Half-Precision Floating-Point Minimal)
fcvt.d.h fa0, ft0 # CHECK: [[@LINE]]:1: error: instruction requires the following: 'Zfh' (Half-Precision Floating-Point) or 'Zfhmin' (Half-Precision Floating-Point Minimal)
fcvt.h.d ft2, fa2 # CHECK: [[@LINE]]:1: error: instruction requires the following: 'Zfh' (Half-Precision Floating-Point) or 'Zfhmin' (Half-Precision Floating-Point Minimal)
56 changes: 56 additions & 0 deletions llvm/test/MC/RISCV/rv32zfbfmin-valid.s
@@ -0,0 +1,56 @@
# RUN: llvm-mc %s -triple=riscv32 -mattr=+experimental-zfbfmin,+f -riscv-no-aliases -show-encoding \
# RUN: | FileCheck -check-prefixes=CHECK-ASM,CHECK-ASM-AND-OBJ %s
# RUN: llvm-mc %s -triple=riscv64 -mattr=+experimental-zfbfmin,+f -riscv-no-aliases -show-encoding \
# RUN: | FileCheck -check-prefixes=CHECK-ASM,CHECK-ASM-AND-OBJ %s
# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=+experimental-zfbfmin,+d < %s \
# RUN: | llvm-objdump --mattr=+experimental-zfbfmin,+f -M no-aliases -d -r - \
# RUN: | FileCheck --check-prefix=CHECK-ASM-AND-OBJ %s
# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+experimental-zfbfmin,+d < %s \
# RUN: | llvm-objdump --mattr=+experimental-zfbfmin,+f -M no-aliases -d -r - \
# RUN: | FileCheck --check-prefix=CHECK-ASM-AND-OBJ %s

# CHECK-ASM-AND-OBJ: flh ft0, 12(a0)
# CHECK-ASM: encoding: [0x07,0x10,0xc5,0x00]
flh f0, 12(a0)
# CHECK-ASM-AND-OBJ: flh ft1, 4(ra)
# CHECK-ASM: encoding: [0x87,0x90,0x40,0x00]
flh f1, +4(ra)
# CHECK-ASM-AND-OBJ: flh ft2, -2048(a3)
# CHECK-ASM: encoding: [0x07,0x91,0x06,0x80]
flh f2, -2048(x13)
# CHECK-ASM-AND-OBJ: flh ft3, -2048(s1)
# CHECK-ASM: encoding: [0x87,0x91,0x04,0x80]
flh f3, %lo(2048)(s1)
# CHECK-ASM-AND-OBJ: flh ft4, 2047(s2)
# CHECK-ASM: encoding: [0x07,0x12,0xf9,0x7f]
flh f4, 2047(s2)
# CHECK-ASM-AND-OBJ: flh ft5, 0(s3)
# CHECK-ASM: encoding: [0x87,0x92,0x09,0x00]
flh f5, 0(s3)

# CHECK-ASM-AND-OBJ: fsh ft6, 2047(s4)
# CHECK-ASM: encoding: [0xa7,0x1f,0x6a,0x7e]
fsh f6, 2047(s4)
# CHECK-ASM-AND-OBJ: fsh ft7, -2048(s5)
# CHECK-ASM: encoding: [0x27,0x90,0x7a,0x80]
fsh f7, -2048(s5)
# CHECK-ASM-AND-OBJ: fsh fs0, -2048(s6)
# CHECK-ASM: encoding: [0x27,0x10,0x8b,0x80]
fsh f8, %lo(2048)(s6)
# CHECK-ASM-AND-OBJ: fsh fs1, 999(s7)
# CHECK-ASM: encoding: [0xa7,0x93,0x9b,0x3e]
fsh f9, 999(s7)

# CHECK-ASM-AND-OBJ: fmv.x.h a2, fs7
# CHECK-ASM: encoding: [0x53,0x86,0x0b,0xe4]
fmv.x.h a2, fs7
# CHECK-ASM-AND-OBJ: fmv.h.x ft1, a6
# CHECK-ASM: encoding: [0xd3,0x00,0x08,0xf4]
fmv.h.x ft1, a6

# CHECK-ASM-AND-OBJ: fcvt.s.bf16 fa0, ft0
# CHECK-ASM: encoding: [0x53,0x75,0x60,0x40]
fcvt.s.bf16 fa0, ft0
# CHECK-ASM-AND-OBJ: fcvt.bf16.s ft2, fa2
# CHECK-ASM: encoding: [0x53,0x71,0x86,0x44]
fcvt.bf16.s ft2, fa2
2 changes: 1 addition & 1 deletion llvm/test/MC/RISCV/rv64zhinx-invalid.s
@@ -1,7 +1,7 @@
# RUN: not llvm-mc -triple riscv64 -mattr=+zhinx %s 2>&1 | FileCheck %s

# Not support float registers
flh fa4, 12(sp) # CHECK: :[[@LINE]]:1: error: instruction requires the following: 'Zfh' (Half-Precision Floating-Point) or 'Zfhmin' (Half-Precision Floating-Point Minimal){{$}}
flh fa4, 12(sp) # CHECK: :[[@LINE]]:1: error: instruction requires the following: 'Zfh' (Half-Precision Floating-Point) or 'Zfhmin' (Half-Precision Floating-Point Minimal) or 'Zfbfmin' (Scalar BF16 Converts){{$}}

# Invalid instructions
fsh a5, 12(sp) # CHECK: :[[@LINE]]:5: error: invalid operand for instruction
Expand Down
2 changes: 1 addition & 1 deletion llvm/test/MC/RISCV/rv64zhinxmin-invalid.s
@@ -1,7 +1,7 @@
# RUN: not llvm-mc -triple riscv64 -mattr=+zhinxmin %s 2>&1 | FileCheck %s

# Not support float registers
flh fa4, 12(sp) # CHECK: :[[@LINE]]:1: error: instruction requires the following: 'Zfh' (Half-Precision Floating-Point) or 'Zfhmin' (Half-Precision Floating-Point Minimal){{$}}
flh fa4, 12(sp) # CHECK: :[[@LINE]]:1: error: instruction requires the following: 'Zfh' (Half-Precision Floating-Point) or 'Zfhmin' (Half-Precision Floating-Point Minimal) or 'Zfbfmin' (Scalar BF16 Converts){{$}}

# Invalid instructions
fsh a5, 12(sp) # CHECK: :[[@LINE]]:5: error: invalid operand for instruction
Expand Down

0 comments on commit 35ff5eb

Please sign in to comment.