authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-12-11 15:18:33+01:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-12-12 17:42:00+01:00
log355b5929b2c49422b92e7aa7374c7e4f0008f400
tree3a191aa6206f967e497e256dd7562c6b5ac985dc
parentc6d654f73bbe80ed3653be6a31ddcaa4772a4fe2
signaturelock-open Commit is signed but in an unrecognized format.

wasm: `splat` for vector elements divisible by 8

This implements `@splat` for vectors where the element type is divisible by 8 and a power of two. This is fairly simple as we can store the values directly within the virtual stack. But for all other sizes, we must first shift and bitwise-or the values before we can store them to fit them like a packed-struct, rather than an array.

1 files changed, 17 insertions(+), 2 deletions(-)

src/arch/wasm/CodeGen.zig+17-2
...@@ -4433,7 +4433,6 @@ fn airSplat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -4433,7 +4433,6 @@ fn airSplat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4433 const ty = func.air.typeOfIndex(inst);4433 const ty = func.air.typeOfIndex(inst);
4434 const elem_ty = ty.childType();4434 const elem_ty = ty.childType();
44354435
4436 const result = try func.allocLocal(ty);
4437 if (determineSimdStoreStrategy(ty, func.target) == .direct) blk: {4436 if (determineSimdStoreStrategy(ty, func.target) == .direct) blk: {
4438 switch (operand) {4437 switch (operand) {
4439 // when the operand lives in the linear memory section, we can directly4438 // when the operand lives in the linear memory section, we can directly
...@@ -4447,6 +4446,7 @@ fn airSplat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -4447,6 +4446,7 @@ fn airSplat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4447 64 => std.wasm.simdOpcode(.v128_load64_splat),4446 64 => std.wasm.simdOpcode(.v128_load64_splat),
4448 else => break :blk, // Cannot make use of simd-instructions4447 else => break :blk, // Cannot make use of simd-instructions
4449 };4448 };
4449 const result = try func.allocLocal(ty);
4450 try func.emitWValue(operand);4450 try func.emitWValue(operand);
4451 // TODO: Add helper functions for simd opcodes4451 // TODO: Add helper functions for simd opcodes
4452 const extra_index = @intCast(u32, func.mir_extra.items.len);4452 const extra_index = @intCast(u32, func.mir_extra.items.len);
...@@ -4468,6 +4468,7 @@ fn airSplat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -4468,6 +4468,7 @@ fn airSplat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4468 64 => if (elem_ty.isInt()) std.wasm.simdOpcode(.i64x2_splat) else std.wasm.simdOpcode(.f64x2_splat),4468 64 => if (elem_ty.isInt()) std.wasm.simdOpcode(.i64x2_splat) else std.wasm.simdOpcode(.f64x2_splat),
4469 else => break :blk, // Cannot make use of simd-instructions4469 else => break :blk, // Cannot make use of simd-instructions
4470 };4470 };
4471 const result = try func.allocLocal(ty);
4471 try func.emitWValue(operand);4472 try func.emitWValue(operand);
4472 const extra_index = @intCast(u32, func.mir_extra.items.len);4473 const extra_index = @intCast(u32, func.mir_extra.items.len);
4473 try func.mir_extra.append(func.gpa, opcode);4474 try func.mir_extra.append(func.gpa, opcode);
...@@ -4478,8 +4479,22 @@ fn airSplat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -4478,8 +4479,22 @@ fn airSplat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4478 else => unreachable,4479 else => unreachable,
4479 }4480 }
4480 }4481 }
4482 const elem_size = elem_ty.bitSize(func.target);
4483 const vector_len = @intCast(usize, ty.vectorLen());
4484 if ((!std.math.isPowerOfTwo(elem_size) or elem_size % 8 != 0) and vector_len > 1) {
4485 return func.fail("TODO: WebAssembly `@splat` for arbitrary element bitsize {d}", .{elem_size});
4486 }
4487
4488 const result = try func.allocStack(ty);
4489 const elem_byte_size = @intCast(u32, elem_ty.abiSize(func.target));
4490 var index: usize = 0;
4491 var offset: u32 = 0;
4492 while (index < vector_len) : (index += 1) {
4493 try func.store(result, operand, elem_ty, offset);
4494 offset += elem_byte_size;
4495 }
44814496
4482 return func.fail("TODO: Implement wasm airSplat unrolled", .{});4497 return func.finishAir(inst, result, &.{ty_op.operand});
4483}4498}
44844499
4485fn airSelect(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {4500fn airSelect(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {