| ... | @@ -1338,11 +1338,21 @@ const SimdStoreStrategy = enum { | ... | @@ -1338,11 +1338,21 @@ const SimdStoreStrategy = enum { |
| 1338 | /// it using a instruction, rather than an unrolled version. | 1338 | /// it using a instruction, rather than an unrolled version. |
| 1339 | pub fn determineSimdStoreStrategy(ty: Type, zcu: *const Zcu, target: *const std.Target) SimdStoreStrategy { | 1339 | pub fn determineSimdStoreStrategy(ty: Type, zcu: *const Zcu, target: *const std.Target) SimdStoreStrategy { |
| 1340 | assert(ty.zigTypeTag(zcu) == .vector); | 1340 | assert(ty.zigTypeTag(zcu) == .vector); |
| 1341 | if (ty.bitSize(zcu) != 128) return .unrolled; | 1341 | if (!target.cpu.has(.wasm, .simd128)) return .unrolled; |
| 1342 | if (target.cpu.has(.wasm, .relaxed_simd) or target.cpu.has(.wasm, .simd128)) { | 1342 | return switch (ty.toIntern()) { |
| 1343 | return .direct; | 1343 | .vector_16_i8_type, |
| 1344 | } | 1344 | .vector_16_u8_type, |
| 1345 | return .unrolled; | 1345 | .vector_8_i16_type, |
| | 1346 | .vector_8_u16_type, |
| | 1347 | .vector_4_i32_type, |
| | 1348 | .vector_4_u32_type, |
| | 1349 | .vector_2_i64_type, |
| | 1350 | .vector_2_u64_type, |
| | 1351 | .vector_4_f32_type, |
| | 1352 | .vector_2_f64_type, |
| | 1353 | => .direct, |
| | 1354 | else => .unrolled, |
| | 1355 | }; |
| 1346 | } | 1356 | } |
| 1347 | | 1357 | |
| 1348 | fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 1358 | fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| ... | @@ -5188,12 +5198,27 @@ fn lowerConstant(cg: *CodeGen, val: Value) InnerError!WValue { | ... | @@ -5188,12 +5198,27 @@ fn lowerConstant(cg: *CodeGen, val: Value) InnerError!WValue { |
| 5188 | } else { | 5198 | } else { |
| 5189 | return .{ .imm32 = @intFromBool(!val.isNull(zcu)) }; | 5199 | return .{ .imm32 = @intFromBool(!val.isNull(zcu)) }; |
| 5190 | }, | 5200 | }, |
| 5191 | .aggregate => switch (ip.indexToKey(ty.ip_index)) { | 5201 | .aggregate => |aggregate| switch (ip.indexToKey(ty.ip_index)) { |
| 5192 | .array_type => return cg.fail("Wasm TODO: LowerConstant for {f}", .{ty.fmt(zcu)}), | 5202 | .array_type => unreachable, |
| 5193 | .vector_type => { | 5203 | .vector_type => |vector_type| { |
| 5194 | assert(determineSimdStoreStrategy(ty, zcu, cg.target) == .direct); | 5204 | assert(determineSimdStoreStrategy(ty, zcu, cg.target) == .direct); |
| 5195 | var buf: [16]u8 = undefined; | 5205 | var buf: [16]u8 = undefined; |
| 5196 | val.writeToMemory(zcu, &buf) catch unreachable; | 5206 | const elem_size: usize = @intCast(Type.fromInterned(vector_type.child).abiSize(zcu)); |
| | 5207 | for (0..vector_type.len) |i| { |
| | 5208 | const dest = buf[i * elem_size ..][0..elem_size]; |
| | 5209 | const elem: Value = switch (aggregate.storage) { |
| | 5210 | .bytes => |bytes| { |
| | 5211 | dest[0] = bytes.at(i, ip); |
| | 5212 | continue; |
| | 5213 | }, |
| | 5214 | .elems => |elems| .fromInterned(elems[i]), |
| | 5215 | .repeated_elem => |elem| .fromInterned(elem), |
| | 5216 | }; |
| | 5217 | elem.writeToMemory(zcu, dest) catch |err| switch (err) { |
| | 5218 | error.OutOfMemory => return error.OutOfMemory, |
| | 5219 | error.ReinterpretDeclRef, error.IllDefinedMemoryLayout => unreachable, |
| | 5220 | }; |
| | 5221 | } |
| 5197 | return cg.storeSimdImmd(buf); | 5222 | return cg.storeSimdImmd(buf); |
| 5198 | }, | 5223 | }, |
| 5199 | .struct_type => unreachable, // packed structs use `bitpack` | 5224 | .struct_type => unreachable, // packed structs use `bitpack` |
| ... | @@ -5216,6 +5241,7 @@ fn storeSimdImmd(cg: *CodeGen, value: [16]u8) !WValue { | ... | @@ -5216,6 +5241,7 @@ fn storeSimdImmd(cg: *CodeGen, value: [16]u8) !WValue { |
| 5216 | fn emitUndefined(cg: *CodeGen, ty: Type) InnerError!WValue { | 5241 | fn emitUndefined(cg: *CodeGen, ty: Type) InnerError!WValue { |
| 5217 | const zcu = cg.pt.zcu; | 5242 | const zcu = cg.pt.zcu; |
| 5218 | switch (ty.zigTypeTag(zcu)) { | 5243 | switch (ty.zigTypeTag(zcu)) { |
| | 5244 | .vector => return cg.storeSimdImmd(@splat(0xaa)), |
| 5219 | .bool, .error_set => return .{ .imm32 = 0xaaaaaaaa }, | 5245 | .bool, .error_set => return .{ .imm32 = 0xaaaaaaaa }, |
| 5220 | .int, .@"enum" => switch (ty.intInfo(zcu).bits) { | 5246 | .int, .@"enum" => switch (ty.intInfo(zcu).bits) { |
| 5221 | 0...32 => return .{ .imm32 = 0xaaaaaaaa }, | 5247 | 0...32 => return .{ .imm32 = 0xaaaaaaaa }, |
| ... | @@ -5785,7 +5811,7 @@ fn bitcast(cg: *CodeGen, dest_ty: Type, src_ty: Type, operand: WValue) InnerErro | ... | @@ -5785,7 +5811,7 @@ fn bitcast(cg: *CodeGen, dest_ty: Type, src_ty: Type, operand: WValue) InnerErro |
| 5785 | .f80, .f128 => unreachable, | 5811 | .f80, .f128 => unreachable, |
| 5786 | }, | 5812 | }, |
| 5787 | .int => {}, | 5813 | .int => {}, |
| 5788 | .aggregate => unreachable, | 5814 | .aggregate => return operand, // both v128 |
| 5789 | } | 5815 | } |
| 5790 | | 5816 | |
| 5791 | switch (dest_class) { | 5817 | switch (dest_class) { |
| ... | @@ -6991,22 +7017,49 @@ fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -6991,22 +7017,49 @@ fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6991 | const result: WValue = result_value: { | 7017 | const result: WValue = result_value: { |
| 6992 | switch (result_ty.zigTypeTag(zcu)) { | 7018 | switch (result_ty.zigTypeTag(zcu)) { |
| 6993 | .array, .vector => { | 7019 | .array, .vector => { |
| 6994 | const result = try cg.allocStack(result_ty); | | |
| 6995 | const elem_ty = result_ty.childType(zcu); | 7020 | const elem_ty = result_ty.childType(zcu); |
| 6996 | const elem_size = elem_ty.abiSize(zcu); | 7021 | if (isByRef(result_ty, zcu, cg.target)) { |
| 6997 | const sentinel = result_ty.sentinel(zcu); | 7022 | const result = try cg.allocStack(result_ty); |
| 6998 | | 7023 | const elem_size = elem_ty.abiSize(zcu); |
| 6999 | var offset: u64 = 0; | 7024 | const sentinel = result_ty.sentinel(zcu); |
| 7000 | for (elements) |elem| { | 7025 | |
| 7001 | const elem_val = try cg.resolveInst(elem); | 7026 | var offset: u64 = 0; |
| 7002 | try cg.store(result, elem_val, elem_ty, .{ .offset = offset }); | 7027 | for (elements) |elem| { |
| 7003 | offset += elem_size; | 7028 | const elem_val = try cg.resolveInst(elem); |
| 7004 | } | 7029 | try cg.store(result, elem_val, elem_ty, .{ .offset = offset }); |
| 7005 | if (sentinel) |s| { | 7030 | offset += elem_size; |
| 7006 | const val = try cg.resolveValue(s); | 7031 | } |
| 7007 | try cg.store(result, val, elem_ty, .{ .offset = offset }); | 7032 | if (sentinel) |s| { |
| | 7033 | const val = try cg.resolveValue(s); |
| | 7034 | try cg.store(result, val, elem_ty, .{ .offset = offset }); |
| | 7035 | } |
| | 7036 | break :result_value result; |
| | 7037 | } else { |
| | 7038 | assert(result_ty.zigTypeTag(zcu) == .vector); |
| | 7039 | const splat: std.wasm.SimdOpcode, const replace_lane: std.wasm.SimdOpcode = switch (elem_ty.toIntern()) { |
| | 7040 | .u8_type, .i8_type => .{ .i8x16_splat, .i8x16_replace_lane }, |
| | 7041 | .u16_type, .i16_type => .{ .i16x8_splat, .i16x8_replace_lane }, |
| | 7042 | .u32_type, .i32_type => .{ .i32x4_splat, .i32x4_replace_lane }, |
| | 7043 | .u64_type, .i64_type => .{ .i64x2_splat, .i64x2_replace_lane }, |
| | 7044 | .f32_type => .{ .f32x4_splat, .f32x4_replace_lane }, |
| | 7045 | .f64_type => .{ .f64x2_splat, .f64x2_replace_lane }, |
| | 7046 | else => unreachable, |
| | 7047 | }; |
| | 7048 | |
| | 7049 | // TODO: find best element to splat, if it is constant dont use splat at all |
| | 7050 | try cg.emitWValue(try cg.resolveInst(elements[0])); |
| | 7051 | const splat_extra: u32 = @intCast(cg.mir_extra.items.len); |
| | 7052 | try cg.mir_extra.append(cg.gpa, @backingInt(splat)); |
| | 7053 | try cg.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = splat_extra } }); |
| | 7054 | for (elements[1..], 1..) |elem, lane| { |
| | 7055 | if (elem == elements[0]) continue; |
| | 7056 | try cg.emitWValue(try cg.resolveInst(elem)); |
| | 7057 | const extra_index: u32 = @intCast(cg.mir_extra.items.len); |
| | 7058 | try cg.mir_extra.appendSlice(cg.gpa, &.{ @backingInt(replace_lane), @intCast(lane) }); |
| | 7059 | try cg.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } }); |
| | 7060 | } |
| | 7061 | break :result_value .stack; |
| 7008 | } | 7062 | } |
| 7009 | break :result_value result; | | |
| 7010 | }, | 7063 | }, |
| 7011 | .@"struct" => switch (result_ty.containerLayout(zcu)) { | 7064 | .@"struct" => switch (result_ty.containerLayout(zcu)) { |
| 7012 | .@"packed" => unreachable, // legalize .expand_packed_aggregate_init | 7065 | .@"packed" => unreachable, // legalize .expand_packed_aggregate_init |
| ... | @@ -7633,7 +7686,7 @@ fn airCmpxchg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7633,7 +7686,7 @@ fn airCmpxchg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7633 | 1 => .i32_atomic_rmw8_cmpxchg_u, | 7686 | 1 => .i32_atomic_rmw8_cmpxchg_u, |
| 7634 | 2 => .i32_atomic_rmw16_cmpxchg_u, | 7687 | 2 => .i32_atomic_rmw16_cmpxchg_u, |
| 7635 | 4 => .i32_atomic_rmw_cmpxchg, | 7688 | 4 => .i32_atomic_rmw_cmpxchg, |
| 7636 | 8 => .i32_atomic_rmw_cmpxchg, | 7689 | 8 => .i64_atomic_rmw_cmpxchg, |
| 7637 | else => |size| return cg.fail("TODO: implement `@cmpxchg` for types with abi size '{d}'", .{size}), | 7690 | else => |size| return cg.fail("TODO: implement `@cmpxchg` for types with abi size '{d}'", .{size}), |
| 7638 | }, .{ | 7691 | }, .{ |
| 7639 | .offset = ptr_operand.memOffset(), | 7692 | .offset = ptr_operand.memOffset(), |
| ... | @@ -7721,6 +7774,9 @@ fn airAtomicRmw(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7721,6 +7774,9 @@ fn airAtomicRmw(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7721 | const op: std.lang.AtomicRmwOp = extra.op(); | 7774 | const op: std.lang.AtomicRmwOp = extra.op(); |
| 7722 | | 7775 | |
| 7723 | if (cg.useAtomicFeature()) { | 7776 | if (cg.useAtomicFeature()) { |
| | 7777 | if (ty.isAnyFloat()) { |
| | 7778 | return cg.fail("TODO: atomic rmw on floats", .{}); |
| | 7779 | } |
| 7724 | const int_ty: IntType = .fromType(cg, ty); | 7780 | const int_ty: IntType = .fromType(cg, ty); |
| 7725 | switch (op) { | 7781 | switch (op) { |
| 7726 | .Max, | 7782 | .Max, |