| ... | @@ -4518,11 +4518,48 @@ fn airArrayElemVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -4518,11 +4518,48 @@ fn airArrayElemVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4518 | const elem_ty = array_ty.childType(); | 4518 | const elem_ty = array_ty.childType(); |
| 4519 | const elem_size = elem_ty.abiSize(func.target); | 4519 | const elem_size = elem_ty.abiSize(func.target); |
| 4520 | | 4520 | |
| 4521 | try func.lowerToStack(array); | 4521 | if (isByRef(array_ty, func.target)) { |
| 4522 | try func.emitWValue(index); | 4522 | try func.lowerToStack(array); |
| 4523 | try func.addImm32(@bitCast(i32, @intCast(u32, elem_size))); | 4523 | try func.emitWValue(index); |
| 4524 | try func.addTag(.i32_mul); | 4524 | try func.addImm32(@bitCast(i32, @intCast(u32, elem_size))); |
| 4525 | try func.addTag(.i32_add); | 4525 | try func.addTag(.i32_mul); |
| | 4526 | try func.addTag(.i32_add); |
| | 4527 | } else { |
| | 4528 | std.debug.assert(array_ty.zigTypeTag() == .Vector); |
| | 4529 | |
| | 4530 | switch (index) { |
| | 4531 | inline .imm32, .imm64 => |lane| { |
| | 4532 | const opcode: wasm.SimdOpcode = switch (elem_ty.bitSize(func.target)) { |
| | 4533 | 8 => if (elem_ty.isSignedInt()) .i8x16_extract_lane_s else .i8x16_extract_lane_u, |
| | 4534 | 16 => if (elem_ty.isSignedInt()) .i16x8_extract_lane_s else .i16x8_extract_lane_u, |
| | 4535 | 32 => if (elem_ty.isInt()) .i32x4_extract_lane else .f32x4_extract_lane, |
| | 4536 | 64 => if (elem_ty.isInt()) .i64x2_extract_lane else .f64x2_extract_lane, |
| | 4537 | else => unreachable, |
| | 4538 | }; |
| | 4539 | |
| | 4540 | var operands = [_]u32{ std.wasm.simdOpcode(opcode), @intCast(u8, lane) }; |
| | 4541 | |
| | 4542 | try func.emitWValue(array); |
| | 4543 | |
| | 4544 | const extra_index = @intCast(u32, func.mir_extra.items.len); |
| | 4545 | try func.mir_extra.appendSlice(func.gpa, &operands); |
| | 4546 | try func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } }); |
| | 4547 | |
| | 4548 | return func.finishAir(inst, try WValue.toLocal(.stack, func, elem_ty), &.{ bin_op.lhs, bin_op.rhs }); |
| | 4549 | }, |
| | 4550 | else => { |
| | 4551 | var stack_vec = try func.allocStack(array_ty); |
| | 4552 | try func.store(stack_vec, array, array_ty, 0); |
| | 4553 | |
| | 4554 | // Is a non-unrolled vector (v128) |
| | 4555 | try func.lowerToStack(stack_vec); |
| | 4556 | try func.emitWValue(index); |
| | 4557 | try func.addImm32(@bitCast(i32, @intCast(u32, elem_size))); |
| | 4558 | try func.addTag(.i32_mul); |
| | 4559 | try func.addTag(.i32_add); |
| | 4560 | }, |
| | 4561 | } |
| | 4562 | } |
| 4526 | | 4563 | |
| 4527 | const elem_result = val: { | 4564 | const elem_result = val: { |
| 4528 | var result = try func.allocLocal(Type.usize); | 4565 | var result = try func.allocLocal(Type.usize); |
| ... | @@ -4670,11 +4707,70 @@ fn airSelect(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -4670,11 +4707,70 @@ fn airSelect(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4670 | } | 4707 | } |
| 4671 | | 4708 | |
| 4672 | fn airShuffle(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 4709 | fn airShuffle(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4673 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; | 4710 | const inst_ty = func.air.typeOfIndex(inst); |
| 4674 | const operand = try func.resolveInst(ty_op.operand); | 4711 | const ty_pl = func.air.instructions.items(.data)[inst].ty_pl; |
| | 4712 | const extra = func.air.extraData(Air.Shuffle, ty_pl.payload).data; |
| 4675 | | 4713 | |
| 4676 | _ = operand; | 4714 | const a = try func.resolveInst(extra.a); |
| 4677 | return func.fail("TODO: Implement wasm airShuffle", .{}); | 4715 | const b = try func.resolveInst(extra.b); |
| | 4716 | const mask = func.air.values[extra.mask]; |
| | 4717 | const mask_len = extra.mask_len; |
| | 4718 | |
| | 4719 | const child_ty = inst_ty.childType(); |
| | 4720 | const elem_size = child_ty.abiSize(func.target); |
| | 4721 | |
| | 4722 | if (func.liveness.isUnused(inst)) { |
| | 4723 | return func.finishAir(inst, .none, &.{ extra.a, extra.b }); |
| | 4724 | } |
| | 4725 | |
| | 4726 | const module = func.bin_file.base.options.module.?; |
| | 4727 | // TODO: One of them could be by ref; handle in loop |
| | 4728 | if (isByRef(func.air.typeOf(extra.a), func.target) or isByRef(inst_ty, func.target)) { |
| | 4729 | const result = try func.allocStack(inst_ty); |
| | 4730 | |
| | 4731 | for (0..mask_len) |index| { |
| | 4732 | var buf: Value.ElemValueBuffer = undefined; |
| | 4733 | const value = mask.elemValueBuffer(module, index, &buf).toSignedInt(func.target); |
| | 4734 | |
| | 4735 | try func.emitWValue(result); |
| | 4736 | |
| | 4737 | const loaded = if (value >= 0) |
| | 4738 | try func.load(a, child_ty, @intCast(u32, @intCast(i64, elem_size) * value)) |
| | 4739 | else |
| | 4740 | try func.load(b, child_ty, @intCast(u32, @intCast(i64, elem_size) * ~value)); |
| | 4741 | |
| | 4742 | try func.store(.stack, loaded, child_ty, result.stack_offset.value + @intCast(u32, elem_size) * @intCast(u32, index)); |
| | 4743 | } |
| | 4744 | |
| | 4745 | return func.finishAir(inst, result, &.{ extra.a, extra.b }); |
| | 4746 | } else { |
| | 4747 | var operands = [_]u32{ |
| | 4748 | std.wasm.simdOpcode(.i8x16_shuffle), |
| | 4749 | } ++ [1]u32{undefined} ** 4; |
| | 4750 | |
| | 4751 | var lanes = std.mem.asBytes(operands[1..]); |
| | 4752 | for (0..@intCast(usize, mask_len)) |index| { |
| | 4753 | var buf: Value.ElemValueBuffer = undefined; |
| | 4754 | const mask_elem = mask.elemValueBuffer(module, index, &buf).toSignedInt(func.target); |
| | 4755 | const base_index = if (mask_elem >= 0) |
| | 4756 | @intCast(u8, @intCast(i64, elem_size) * mask_elem) |
| | 4757 | else |
| | 4758 | 16 + @intCast(u8, @intCast(i64, elem_size) * ~mask_elem); |
| | 4759 | |
| | 4760 | for (0..@intCast(usize, elem_size)) |byte_offset| { |
| | 4761 | lanes[index * @intCast(usize, elem_size) + byte_offset] = base_index + @intCast(u8, byte_offset); |
| | 4762 | } |
| | 4763 | } |
| | 4764 | |
| | 4765 | try func.emitWValue(a); |
| | 4766 | try func.emitWValue(b); |
| | 4767 | |
| | 4768 | const extra_index = @intCast(u32, func.mir_extra.items.len); |
| | 4769 | try func.mir_extra.appendSlice(func.gpa, &operands); |
| | 4770 | try func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } }); |
| | 4771 | |
| | 4772 | return func.finishAir(inst, try WValue.toLocal(.stack, func, inst_ty), &.{ extra.a, extra.b }); |
| | 4773 | } |
| 4678 | } | 4774 | } |
| 4679 | | 4775 | |
| 4680 | fn airReduce(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 4776 | fn airReduce(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| ... | @@ -5125,7 +5221,12 @@ fn airMemcpy(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -5125,7 +5221,12 @@ fn airMemcpy(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5125 | } | 5221 | } |
| 5126 | | 5222 | |
| 5127 | fn airRetAddr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 5223 | fn airRetAddr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5128 | func.finishAir(inst, .{ .imm32 = 0 }, &.{}); | 5224 | // TODO: Implement this properly once stack serialization is solved |
| | 5225 | func.finishAir(inst, switch (func.arch()) { |
| | 5226 | .wasm32 => .{ .imm32 = 0 }, |
| | 5227 | .wasm64 => .{ .imm64 = 0 }, |
| | 5228 | else => unreachable, |
| | 5229 | }, &.{}); |
| 5129 | } | 5230 | } |
| 5130 | | 5231 | |
| 5131 | fn airPopcount(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 5232 | fn airPopcount(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |