Skip to content

[Work-in-Progress][Clang][RISCV] Create supporting intrinsics around RVV BFloat16 type #72463

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

Closed
wants to merge 2 commits into from
Closed
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
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/riscv_vector.td
Original file line number Diff line number Diff line change
Expand Up @@ -683,6 +683,8 @@ defm vle8: RVVVLEBuiltin<["c"]>;
defm vle16: RVVVLEBuiltin<["s"]>;
let Name = "vle16_v", RequiredFeatures = ["ZvfhminOrZvfh"] in
defm vle16_h: RVVVLEBuiltin<["x"]>;
let Name = "vle16_v", RequiredFeatures = ["Zvfbfmin"] in
defm vle16_b: RVVVLEBuiltin<["b"]>;
defm vle32: RVVVLEBuiltin<["i","f"]>;
defm vle64: RVVVLEBuiltin<["l","d"]>;

Expand Down
8 changes: 5 additions & 3 deletions clang/include/clang/Support/RISCVVIntrinsicUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -485,7 +485,8 @@ class RVVIntrinsic {

// RVVRequire should be sync'ed with target features, but only
// required features used in riscv_vector.td.
enum RVVRequire : uint16_t {
using RVVRequireT = uint32_t;
enum RVVRequire : RVVRequireT {
RVV_REQ_None = 0,
RVV_REQ_RV64 = 1 << 0,
RVV_REQ_ZvfhminOrZvfh = 1 << 1,
Expand All @@ -503,8 +504,9 @@ enum RVVRequire : uint16_t {
RVV_REQ_Zvknhb = 1 << 13,
RVV_REQ_Zvksed = 1 << 14,
RVV_REQ_Zvksh = 1 << 15,
RVV_REQ_Zvfbfmin = 1 << 16,

LLVM_MARK_AS_BITMASK_ENUM(RVV_REQ_Zvksh)
LLVM_MARK_AS_BITMASK_ENUM(RVV_REQ_Zvfbfmin)
};

// Raw RVV intrinsic info, used to expand later.
Expand Down Expand Up @@ -536,7 +538,7 @@ struct RVVIntrinsicRecord {
uint8_t OverloadedSuffixSize;

// Required target features for this intrinsic.
uint16_t RequiredExtensions;
RVVRequireT RequiredExtensions;

// Supported type, mask of BasicType.
uint8_t TypeRangeMask;
Expand Down
10 changes: 10 additions & 0 deletions clang/lib/Sema/SemaRISCVVectorLookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,16 @@ void RISCVIntrinsicManagerImpl::ConstructRVVIntrinsics(
}
}

if (BaseType == BasicType::BFloat16) {
if (Record.RequiredExtensions & RVV_REQ_Zvfbfmin) {
if (!TI.hasFeature("experimental-zvfbfmin"))
continue;
} else {
llvm_unreachable_internal(
"Non-basic BFloat16 intrinsics are not implemented yet.");
}
}

// Expanded with different LMUL.
for (int Log2LMUL = -3; Log2LMUL <= 3; Log2LMUL++) {
if (!(Record.Log2LMULMask & (1 << (Log2LMUL + 3))))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 4
// REQUIRES: riscv-registered-target
// RUN: %clang_cc1 -triple riscv64 -target-feature +v -target-feature +zfh \
// RUN: -target-feature +experimental-zvfbfmin \
// RUN: -target-feature +zvfh -disable-O0-optnone \
// RUN: -emit-llvm %s -o - | opt -S -passes=mem2reg | \
// RUN: FileCheck --check-prefix=CHECK-RV64 %s

#include <riscv_vector.h>

// CHECK-RV64-LABEL: define dso_local <vscale x 1 x bfloat> @test_vle16_v_bf16mf4(
// CHECK-RV64-SAME: ptr noundef [[RS1:%.*]], i64 noundef [[VL:%.*]]) #[[ATTR0:[0-9]+]] {
// CHECK-RV64-NEXT: entry:
// CHECK-RV64-NEXT: [[TMP0:%.*]] = call <vscale x 1 x bfloat> @llvm.riscv.vle.nxv1bf16.i64(<vscale x 1 x bfloat> poison, ptr [[RS1]], i64 [[VL]])
// CHECK-RV64-NEXT: ret <vscale x 1 x bfloat> [[TMP0]]
//
vbfloat16mf4_t test_vle16_v_bf16mf4(const __bf16 *rs1, size_t vl) {
return __riscv_vle16_v_bf16mf4(rs1, vl);
}

// CHECK-RV64-LABEL: define dso_local <vscale x 2 x bfloat> @test_vle16_v_bf16mf2(
// CHECK-RV64-SAME: ptr noundef [[RS1:%.*]], i64 noundef [[VL:%.*]]) #[[ATTR0]] {
// CHECK-RV64-NEXT: entry:
// CHECK-RV64-NEXT: [[TMP0:%.*]] = call <vscale x 2 x bfloat> @llvm.riscv.vle.nxv2bf16.i64(<vscale x 2 x bfloat> poison, ptr [[RS1]], i64 [[VL]])
// CHECK-RV64-NEXT: ret <vscale x 2 x bfloat> [[TMP0]]
//
vbfloat16mf2_t test_vle16_v_bf16mf2(const __bf16 *rs1, size_t vl) {
return __riscv_vle16_v_bf16mf2(rs1, vl);
}

// CHECK-RV64-LABEL: define dso_local <vscale x 4 x bfloat> @test_vle16_v_bf16m1(
// CHECK-RV64-SAME: ptr noundef [[RS1:%.*]], i64 noundef [[VL:%.*]]) #[[ATTR0]] {
// CHECK-RV64-NEXT: entry:
// CHECK-RV64-NEXT: [[TMP0:%.*]] = call <vscale x 4 x bfloat> @llvm.riscv.vle.nxv4bf16.i64(<vscale x 4 x bfloat> poison, ptr [[RS1]], i64 [[VL]])
// CHECK-RV64-NEXT: ret <vscale x 4 x bfloat> [[TMP0]]
//
vbfloat16m1_t test_vle16_v_bf16m1(const __bf16 *rs1, size_t vl) {
return __riscv_vle16_v_bf16m1(rs1, vl);
}

// CHECK-RV64-LABEL: define dso_local <vscale x 8 x bfloat> @test_vle16_v_bf16m2(
// CHECK-RV64-SAME: ptr noundef [[RS1:%.*]], i64 noundef [[VL:%.*]]) #[[ATTR0]] {
// CHECK-RV64-NEXT: entry:
// CHECK-RV64-NEXT: [[TMP0:%.*]] = call <vscale x 8 x bfloat> @llvm.riscv.vle.nxv8bf16.i64(<vscale x 8 x bfloat> poison, ptr [[RS1]], i64 [[VL]])
// CHECK-RV64-NEXT: ret <vscale x 8 x bfloat> [[TMP0]]
//
vbfloat16m2_t test_vle16_v_bf16m2(const __bf16 *rs1, size_t vl) {
return __riscv_vle16_v_bf16m2(rs1, vl);
}

// CHECK-RV64-LABEL: define dso_local <vscale x 16 x bfloat> @test_vle16_v_bf16m4(
// CHECK-RV64-SAME: ptr noundef [[RS1:%.*]], i64 noundef [[VL:%.*]]) #[[ATTR0]] {
// CHECK-RV64-NEXT: entry:
// CHECK-RV64-NEXT: [[TMP0:%.*]] = call <vscale x 16 x bfloat> @llvm.riscv.vle.nxv16bf16.i64(<vscale x 16 x bfloat> poison, ptr [[RS1]], i64 [[VL]])
// CHECK-RV64-NEXT: ret <vscale x 16 x bfloat> [[TMP0]]
//
vbfloat16m4_t test_vle16_v_bf16m4(const __bf16 *rs1, size_t vl) {
return __riscv_vle16_v_bf16m4(rs1, vl);
}

// CHECK-RV64-LABEL: define dso_local <vscale x 32 x bfloat> @test_vle16_v_bf16m8(
// CHECK-RV64-SAME: ptr noundef [[RS1:%.*]], i64 noundef [[VL:%.*]]) #[[ATTR0]] {
// CHECK-RV64-NEXT: entry:
// CHECK-RV64-NEXT: [[TMP0:%.*]] = call <vscale x 32 x bfloat> @llvm.riscv.vle.nxv32bf16.i64(<vscale x 32 x bfloat> poison, ptr [[RS1]], i64 [[VL]])
// CHECK-RV64-NEXT: ret <vscale x 32 x bfloat> [[TMP0]]
//
vbfloat16m8_t test_vle16_v_bf16m8(const __bf16 *rs1, size_t vl) {
return __riscv_vle16_v_bf16m8(rs1, vl);
}

// CHECK-RV64-LABEL: define dso_local <vscale x 1 x bfloat> @test_vle16_v_bf16mf4_m(
// CHECK-RV64-SAME: <vscale x 1 x i1> [[VM:%.*]], ptr noundef [[RS1:%.*]], i64 noundef [[VL:%.*]]) #[[ATTR0]] {
// CHECK-RV64-NEXT: entry:
// CHECK-RV64-NEXT: [[TMP0:%.*]] = call <vscale x 1 x bfloat> @llvm.riscv.vle.mask.nxv1bf16.i64(<vscale x 1 x bfloat> poison, ptr [[RS1]], <vscale x 1 x i1> [[VM]], i64 [[VL]], i64 3)
// CHECK-RV64-NEXT: ret <vscale x 1 x bfloat> [[TMP0]]
//
vbfloat16mf4_t test_vle16_v_bf16mf4_m(vbool64_t vm, const __bf16 *rs1,
size_t vl) {
return __riscv_vle16_v_bf16mf4_m(vm, rs1, vl);
}

// CHECK-RV64-LABEL: define dso_local <vscale x 2 x bfloat> @test_vle16_v_bf16mf2_m(
// CHECK-RV64-SAME: <vscale x 2 x i1> [[VM:%.*]], ptr noundef [[RS1:%.*]], i64 noundef [[VL:%.*]]) #[[ATTR0]] {
// CHECK-RV64-NEXT: entry:
// CHECK-RV64-NEXT: [[TMP0:%.*]] = call <vscale x 2 x bfloat> @llvm.riscv.vle.mask.nxv2bf16.i64(<vscale x 2 x bfloat> poison, ptr [[RS1]], <vscale x 2 x i1> [[VM]], i64 [[VL]], i64 3)
// CHECK-RV64-NEXT: ret <vscale x 2 x bfloat> [[TMP0]]
//
vbfloat16mf2_t test_vle16_v_bf16mf2_m(vbool32_t vm, const __bf16 *rs1,
size_t vl) {
return __riscv_vle16_v_bf16mf2_m(vm, rs1, vl);
}

// CHECK-RV64-LABEL: define dso_local <vscale x 4 x bfloat> @test_vle16_v_bf16m1_m(
// CHECK-RV64-SAME: <vscale x 4 x i1> [[VM:%.*]], ptr noundef [[RS1:%.*]], i64 noundef [[VL:%.*]]) #[[ATTR0]] {
// CHECK-RV64-NEXT: entry:
// CHECK-RV64-NEXT: [[TMP0:%.*]] = call <vscale x 4 x bfloat> @llvm.riscv.vle.mask.nxv4bf16.i64(<vscale x 4 x bfloat> poison, ptr [[RS1]], <vscale x 4 x i1> [[VM]], i64 [[VL]], i64 3)
// CHECK-RV64-NEXT: ret <vscale x 4 x bfloat> [[TMP0]]
//
vbfloat16m1_t test_vle16_v_bf16m1_m(vbool16_t vm, const __bf16 *rs1,
size_t vl) {
return __riscv_vle16_v_bf16m1_m(vm, rs1, vl);
}

// CHECK-RV64-LABEL: define dso_local <vscale x 8 x bfloat> @test_vle16_v_bf16m2_m(
// CHECK-RV64-SAME: <vscale x 8 x i1> [[VM:%.*]], ptr noundef [[RS1:%.*]], i64 noundef [[VL:%.*]]) #[[ATTR0]] {
// CHECK-RV64-NEXT: entry:
// CHECK-RV64-NEXT: [[TMP0:%.*]] = call <vscale x 8 x bfloat> @llvm.riscv.vle.mask.nxv8bf16.i64(<vscale x 8 x bfloat> poison, ptr [[RS1]], <vscale x 8 x i1> [[VM]], i64 [[VL]], i64 3)
// CHECK-RV64-NEXT: ret <vscale x 8 x bfloat> [[TMP0]]
//
vbfloat16m2_t test_vle16_v_bf16m2_m(vbool8_t vm, const __bf16 *rs1, size_t vl) {
return __riscv_vle16_v_bf16m2_m(vm, rs1, vl);
}

// CHECK-RV64-LABEL: define dso_local <vscale x 16 x bfloat> @test_vle16_v_bf16m4_m(
// CHECK-RV64-SAME: <vscale x 16 x i1> [[VM:%.*]], ptr noundef [[RS1:%.*]], i64 noundef [[VL:%.*]]) #[[ATTR0]] {
// CHECK-RV64-NEXT: entry:
// CHECK-RV64-NEXT: [[TMP0:%.*]] = call <vscale x 16 x bfloat> @llvm.riscv.vle.mask.nxv16bf16.i64(<vscale x 16 x bfloat> poison, ptr [[RS1]], <vscale x 16 x i1> [[VM]], i64 [[VL]], i64 3)
// CHECK-RV64-NEXT: ret <vscale x 16 x bfloat> [[TMP0]]
//
vbfloat16m4_t test_vle16_v_bf16m4_m(vbool4_t vm, const __bf16 *rs1, size_t vl) {
return __riscv_vle16_v_bf16m4_m(vm, rs1, vl);
}

// CHECK-RV64-LABEL: define dso_local <vscale x 32 x bfloat> @test_vle16_v_bf16m8_m(
// CHECK-RV64-SAME: <vscale x 32 x i1> [[VM:%.*]], ptr noundef [[RS1:%.*]], i64 noundef [[VL:%.*]]) #[[ATTR0]] {
// CHECK-RV64-NEXT: entry:
// CHECK-RV64-NEXT: [[TMP0:%.*]] = call <vscale x 32 x bfloat> @llvm.riscv.vle.mask.nxv32bf16.i64(<vscale x 32 x bfloat> poison, ptr [[RS1]], <vscale x 32 x i1> [[VM]], i64 [[VL]], i64 3)
// CHECK-RV64-NEXT: ret <vscale x 32 x bfloat> [[TMP0]]
//
vbfloat16m8_t test_vle16_v_bf16m8_m(vbool2_t vm, const __bf16 *rs1, size_t vl) {
return __riscv_vle16_v_bf16m8_m(vm, rs1, vl);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
// REQUIRES: riscv-registered-target
// RUN: %clang_cc1 -triple riscv64 -target-feature +v \
// RUN: -target-feature +experimental-zvfbfmin -disable-O0-optnone \
// RUN: -emit-llvm %s -o - | opt -S -passes=mem2reg | \
// RUN: FileCheck --check-prefix=CHECK-ZVFBFMIN %s

// RUN: not %clang_cc1 -triple riscv64 -target-feature +v \
// RUN: -target-feature +zvfhmin -emit-llvm-only %s 2>&1 | \
// RUN: FileCheck %s --check-prefix=CHECK-ZVFBFMIN-ERR

#include <riscv_vector.h>

// CHECK-ZVFBFMIN-LABEL: @test_vle16_v_bf16mf4(
// CHECK-ZVFBFMIN-NEXT: entry:
// CHECK-ZVFBFMIN-NEXT: [[TMP0:%.*]] = call <vscale x 1 x bfloat> @llvm.riscv.vle.nxv1bf16.i64(<vscale x 1 x bfloat> poison, ptr [[RS1:%.*]], i64 [[VL:%.*]])
// CHECK-ZVFBFMIN-NEXT: ret <vscale x 1 x bfloat> [[TMP0]]
//

// CHECK-ZVFBFMIN-ERR: error: call to undeclared function '__riscv_vle16_v_bf16mf4'

vbfloat16mf4_t test_vle16_v_bf16mf4(const __bf16 *rs1, size_t vl) {
return __riscv_vle16_v_bf16mf4(rs1, vl);
}
40 changes: 21 additions & 19 deletions clang/utils/TableGen/RISCVVEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ struct SemaRecord {
unsigned Log2LMULMask;

// Required extensions for this intrinsic.
unsigned RequiredExtensions;
RVVRequireT RequiredExtensions;

// Prototype for this intrinsic.
SmallVector<PrototypeDescriptor> Prototype;
Expand Down Expand Up @@ -656,24 +656,26 @@ void RVVEmitter::createRVVIntrinsics(

SR.RequiredExtensions = 0;
for (auto RequiredFeature : RequiredFeatures) {
RVVRequire RequireExt = StringSwitch<RVVRequire>(RequiredFeature)
.Case("RV64", RVV_REQ_RV64)
.Case("ZvfhminOrZvfh", RVV_REQ_ZvfhminOrZvfh)
.Case("Xsfvcp", RVV_REQ_Xsfvcp)
.Case("Xsfvfnrclipxfqf", RVV_REQ_Xsfvfnrclipxfqf)
.Case("Xsfvfwmaccqqq", RVV_REQ_Xsfvfwmaccqqq)
.Case("Xsfvqmaccdod", RVV_REQ_Xsfvqmaccdod)
.Case("Xsfvqmaccqoq", RVV_REQ_Xsfvqmaccqoq)
.Case("Zvbb", RVV_REQ_Zvbb)
.Case("Zvbc", RVV_REQ_Zvbc)
.Case("Zvkb", RVV_REQ_Zvkb)
.Case("Zvkg", RVV_REQ_Zvkg)
.Case("Zvkned", RVV_REQ_Zvkned)
.Case("Zvknha", RVV_REQ_Zvknha)
.Case("Zvknhb", RVV_REQ_Zvknhb)
.Case("Zvksed", RVV_REQ_Zvksed)
.Case("Zvksh", RVV_REQ_Zvksh)
.Default(RVV_REQ_None);
RVVRequire RequireExt =
StringSwitch<RVVRequire>(RequiredFeature)
.Case("RV64", RVV_REQ_RV64)
.Case("ZvfhminOrZvfh", RVV_REQ_ZvfhminOrZvfh)
.Case("Xsfvcp", RVV_REQ_Xsfvcp)
.Case("Xsfvfnrclipxfqf", RVV_REQ_Xsfvfnrclipxfqf)
.Case("Xsfvfwmaccqqq", RVV_REQ_Xsfvfwmaccqqq)
.Case("Xsfvqmaccdod", RVV_REQ_Xsfvqmaccdod)
.Case("Xsfvqmaccqoq", RVV_REQ_Xsfvqmaccqoq)
.Case("Zvbb", RVV_REQ_Zvbb)
.Case("Zvbc", RVV_REQ_Zvbc)
.Case("Zvkb", RVV_REQ_Zvkb)
.Case("Zvkg", RVV_REQ_Zvkg)
.Case("Zvkned", RVV_REQ_Zvkned)
.Case("Zvknha", RVV_REQ_Zvknha)
.Case("Zvknhb", RVV_REQ_Zvknhb)
.Case("Zvksed", RVV_REQ_Zvksed)
.Case("Zvksh", RVV_REQ_Zvksh)
.Case("Zvfbfmin", RVV_REQ_Zvfbfmin)
.Default(RVV_REQ_None);
assert(RequireExt != RVV_REQ_None && "Unrecognized required feature?");
SR.RequiredExtensions |= RequireExt;
}
Expand Down