Skip to content

Commit 09c5525

Browse files
authored
[WebAssembly] Implement prototype f16x8.splat instruction. (#93228)
Adds a builtin and intrinsic for the f16x8.splat instruction. Specified at: https://github.com/WebAssembly/half-precision/blob/29a9b9462c9285d4ccc1a5dc39214ddfd1892658/proposals/half-precision/Overview.md Note: the current spec has f16x8.splat as opcode 0x123, but this is incorrect and will be changed to 0x120 soon.
1 parent d1d9545 commit 09c5525

File tree

11 files changed

+54
-4
lines changed

11 files changed

+54
-4
lines changed

clang/include/clang/Basic/BuiltinsWebAssembly.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ TARGET_BUILTIN(__builtin_wasm_relaxed_dot_bf16x8_add_f32_f32x4, "V4fV8UsV8UsV4f"
193193
// Half-Precision (fp16)
194194
TARGET_BUILTIN(__builtin_wasm_loadf16_f32, "fh*", "nU", "half-precision")
195195
TARGET_BUILTIN(__builtin_wasm_storef16_f32, "vfh*", "n", "half-precision")
196+
TARGET_BUILTIN(__builtin_wasm_splat_f16x8, "V8hf", "nc", "half-precision")
196197

197198
// Reference Types builtins
198199
// Some builtins are custom type-checked - see 't' as part of the third argument,

clang/lib/Basic/Targets/WebAssembly.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,9 @@ class LLVM_LIBRARY_VISIBILITY WebAssemblyTargetInfo : public TargetInfo {
9090

9191
StringRef getABI() const override;
9292
bool setABI(const std::string &Name) override;
93+
bool useFP16ConversionIntrinsics() const override {
94+
return !HasHalfPrecision;
95+
}
9396

9497
protected:
9598
void getTargetDefines(const LangOptions &Opts,

clang/lib/CodeGen/CGBuiltin.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21230,6 +21230,11 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID,
2123021230
Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_storef16_f32);
2123121231
return Builder.CreateCall(Callee, {Val, Addr});
2123221232
}
21233+
case WebAssembly::BI__builtin_wasm_splat_f16x8: {
21234+
Value *Val = EmitScalarExpr(E->getArg(0));
21235+
Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_splat_f16x8);
21236+
return Builder.CreateCall(Callee, {Val});
21237+
}
2123321238
case WebAssembly::BI__builtin_wasm_table_get: {
2123421239
assert(E->getArg(0)->getType()->isArrayType());
2123521240
Value *Table = EmitArrayToPointerDecay(E->getArg(0)).emitRawPointer(*this);

clang/test/CodeGen/builtins-wasm.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ typedef unsigned char u8x16 __attribute((vector_size(16)));
1111
typedef unsigned short u16x8 __attribute((vector_size(16)));
1212
typedef unsigned int u32x4 __attribute((vector_size(16)));
1313
typedef unsigned long long u64x2 __attribute((vector_size(16)));
14+
typedef __fp16 f16x8 __attribute((vector_size(16)));
1415
typedef float f32x4 __attribute((vector_size(16)));
1516
typedef double f64x2 __attribute((vector_size(16)));
1617

@@ -813,6 +814,11 @@ void store_f16_f32(float val, __fp16 *addr) {
813814
// WEBASSEMBLY-NEXT: ret
814815
}
815816

817+
f16x8 splat_f16x8(float a) {
818+
// WEBASSEMBLY: %0 = tail call <8 x half> @llvm.wasm.splat.f16x8(float %a)
819+
// WEBASSEMBLY-NEXT: ret <8 x half> %0
820+
return __builtin_wasm_splat_f16x8(a);
821+
}
816822
__externref_t externref_null() {
817823
return __builtin_wasm_ref_null_extern();
818824
// WEBASSEMBLY: tail call ptr addrspace(10) @llvm.wasm.ref.null.extern()

llvm/include/llvm/IR/IntrinsicsWebAssembly.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,10 @@ def int_wasm_storef16_f32:
337337
[llvm_float_ty, llvm_ptr_ty],
338338
[IntrWriteMem, IntrArgMemOnly],
339339
"", [SDNPMemOperand]>;
340+
def int_wasm_splat_f16x8:
341+
DefaultAttrsIntrinsic<[llvm_v8f16_ty],
342+
[llvm_float_ty],
343+
[IntrNoMem, IntrSpeculatable]>;
340344

341345

342346
//===----------------------------------------------------------------------===//

llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ wasm::ValType WebAssembly::toValType(MVT Type) {
5050
case MVT::v8i16:
5151
case MVT::v4i32:
5252
case MVT::v2i64:
53+
case MVT::v8f16:
5354
case MVT::v4f32:
5455
case MVT::v2f64:
5556
return wasm::ValType::V128;

llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ WebAssemblyTargetLowering::WebAssemblyTargetLowering(
7070
addRegisterClass(MVT::v2i64, &WebAssembly::V128RegClass);
7171
addRegisterClass(MVT::v2f64, &WebAssembly::V128RegClass);
7272
}
73+
if (Subtarget->hasHalfPrecision()) {
74+
addRegisterClass(MVT::v8f16, &WebAssembly::V128RegClass);
75+
}
7376
if (Subtarget->hasReferenceTypes()) {
7477
addRegisterClass(MVT::externref, &WebAssembly::EXTERNREFRegClass);
7578
addRegisterClass(MVT::funcref, &WebAssembly::FUNCREFRegClass);

llvm/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,13 @@ multiclass RELAXED_I<dag oops_r, dag iops_r, dag oops_s, dag iops_s,
3838
asmstr_s, simdop, HasRelaxedSIMD>;
3939
}
4040

41+
multiclass HALF_PRECISION_I<dag oops_r, dag iops_r, dag oops_s, dag iops_s,
42+
list<dag> pattern_r, string asmstr_r = "",
43+
string asmstr_s = "", bits<32> simdop = -1> {
44+
defm "" : ABSTRACT_SIMD_I<oops_r, iops_r, oops_s, iops_s, pattern_r, asmstr_r,
45+
asmstr_s, simdop, HasHalfPrecision>;
46+
}
47+
4148

4249
defm "" : ARGUMENT<V128, v16i8>;
4350
defm "" : ARGUMENT<V128, v8i16>;
@@ -591,6 +598,14 @@ defm "" : Splat<I64x2, 18>;
591598
defm "" : Splat<F32x4, 19>;
592599
defm "" : Splat<F64x2, 20>;
593600

601+
// Half values are not fully supported so an intrinsic is used instead of a
602+
// regular Splat pattern as above.
603+
defm SPLAT_F16x8 :
604+
HALF_PRECISION_I<(outs V128:$dst), (ins F32:$x),
605+
(outs), (ins),
606+
[(set (v8f16 V128:$dst), (int_wasm_splat_f16x8 F32:$x))],
607+
"f16x8.splat\t$dst, $x", "f16x8.splat", 0x120>;
608+
594609
// scalar_to_vector leaves high lanes undefined, so can be a splat
595610
foreach vec = AllVecs in
596611
def : Pat<(vec.vt (scalar_to_vector (vec.lane_vt vec.lane_rc:$x))),

llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.td

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,8 @@ def I32 : WebAssemblyRegClass<[i32], 32, (add FP32, SP32, I32_0)>;
6363
def I64 : WebAssemblyRegClass<[i64], 64, (add FP64, SP64, I64_0)>;
6464
def F32 : WebAssemblyRegClass<[f32], 32, (add F32_0)>;
6565
def F64 : WebAssemblyRegClass<[f64], 64, (add F64_0)>;
66-
def V128 : WebAssemblyRegClass<[v4f32, v2f64, v2i64, v4i32, v16i8, v8i16], 128,
67-
(add V128_0)>;
66+
def V128 : WebAssemblyRegClass<[v8f16, v4f32, v2f64, v2i64, v4i32, v16i8,
67+
v8i16],
68+
128, (add V128_0)>;
6869
def FUNCREF : WebAssemblyRegClass<[funcref], 0, (add FUNCREF_0)>;
6970
def EXTERNREF : WebAssemblyRegClass<[externref], 0, (add EXTERNREF_0)>;

llvm/test/CodeGen/WebAssembly/half-precision.ll

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
; RUN: llc < %s --mtriple=wasm32-unknown-unknown -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -mattr=+half-precision | FileCheck %s
2-
; RUN: llc < %s --mtriple=wasm64-unknown-unknown -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -mattr=+half-precision | FileCheck %s
1+
; RUN: llc < %s --mtriple=wasm32-unknown-unknown -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -mattr=+half-precision,+simd128 | FileCheck %s
2+
; RUN: llc < %s --mtriple=wasm64-unknown-unknown -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -mattr=+half-precision,+simd128 | FileCheck %s
33

44
declare float @llvm.wasm.loadf32.f16(ptr)
55
declare void @llvm.wasm.storef16.f32(float, ptr)
@@ -19,3 +19,11 @@ define void @stf16_32(float %v, ptr %p) {
1919
tail call void @llvm.wasm.storef16.f32(float %v, ptr %p)
2020
ret void
2121
}
22+
23+
; CHECK-LABEL: splat_v8f16:
24+
; CHECK: f16x8.splat $push0=, $0
25+
; CHECK-NEXT: return $pop0
26+
define <8 x half> @splat_v8f16(float %x) {
27+
%v = call <8 x half> @llvm.wasm.splat.f16x8(float %x)
28+
ret <8 x half> %v
29+
}

llvm/test/MC/WebAssembly/simd-encodings.s

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -845,4 +845,7 @@ main:
845845
# CHECK: f32.store_f16 32 # encoding: [0xfc,0x31,0x01,0x20]
846846
f32.store_f16 32
847847

848+
# CHECK: f16x8.splat # encoding: [0xfd,0xa0,0x02]
849+
f16x8.splat
850+
848851
end_function

0 commit comments

Comments
 (0)