| ... | ... | @@ -2519,8 +2519,16 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 2519 | 2519 | if (!err_ty.errorUnionPayload().hasRuntimeBits()) return operand; |
| 2520 | 2520 | |
| 2521 | 2521 | const err_union = try self.allocStack(err_ty); |
| 2522 | | // TODO: Also write 'undefined' to the payload |
| 2523 | 2522 | try self.store(err_union, operand, err_ty.errorUnionSet(), 0); |
| 2523 | |
| 2524 | // write 'undefined' to the payload |
| 2525 | const err_align = err_ty.abiAlignment(self.target); |
| 2526 | const set_size = err_ty.errorUnionSet().abiSize(self.target); |
| 2527 | const offset = mem.alignForwardGeneric(u64, set_size, err_align); |
| 2528 | const payload_ptr = try self.buildPointerOffset(err_union, offset, .new); |
| 2529 | const len = @intCast(u32, err_ty.errorUnionPayload().abiSize(self.target)); |
| 2530 | try self.memset(payload_ptr, .{ .imm32 = len }, .{ .imm32 = 0xaaaaaaaa }); |
| 2531 | |
| 2524 | 2532 | return err_union; |
| 2525 | 2533 | } |
| 2526 | 2534 | |
| ... | ... | @@ -2972,7 +2980,7 @@ fn airMemset(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 2972 | 2980 | const ptr = try self.resolveInst(pl_op.operand); |
| 2973 | 2981 | const value = try self.resolveInst(bin_op.lhs); |
| 2974 | 2982 | const len = try self.resolveInst(bin_op.rhs); |
| 2975 | | try self.memSet(ptr, len, value); |
| 2983 | try self.memset(ptr, len, value); |
| 2976 | 2984 | |
| 2977 | 2985 | return WValue{ .none = {} }; |
| 2978 | 2986 | } |
| ... | ... | @@ -2981,7 +2989,7 @@ fn airMemset(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 2981 | 2989 | /// When the user has enabled the bulk_memory feature, we lower |
| 2982 | 2990 | /// this to wasm's memset instruction. When the feature is not present, |
| 2983 | 2991 | /// we implement it manually. |
| 2984 | | fn memSet(self: *Self, ptr: WValue, len: WValue, value: WValue) InnerError!void { |
| 2992 | fn memset(self: *Self, ptr: WValue, len: WValue, value: WValue) InnerError!void { |
| 2985 | 2993 | // When bulk_memory is enabled, we lower it to wasm's memset instruction. |
| 2986 | 2994 | // If not, we lower it ourselves |
| 2987 | 2995 | if (std.Target.wasm.featureSetHas(self.target.cpu.features, .bulk_memory)) { |
| ... | ... | @@ -2995,45 +3003,74 @@ fn memSet(self: *Self, ptr: WValue, len: WValue, value: WValue) InnerError!void |
| 2995 | 3003 | return; |
| 2996 | 3004 | } |
| 2997 | 3005 | |
| 2998 | | // TODO: We should probably lower this to a call to compiler_rt |
| 2999 | | // But for now, we implement it manually |
| 3000 | | const offset = try self.allocLocal(Type.usize); // local for counter |
| 3001 | | // outer block to jump to when loop is done |
| 3002 | | try self.startBlock(.block, wasm.block_empty); |
| 3003 | | try self.startBlock(.loop, wasm.block_empty); |
| 3004 | | try self.emitWValue(offset); |
| 3005 | | try self.emitWValue(len); |
| 3006 | | switch (self.ptrSize()) { |
| 3007 | | 4 => try self.addTag(.i32_eq), |
| 3008 | | 8 => try self.addTag(.i64_eq), |
| 3009 | | else => unreachable, |
| 3010 | | } |
| 3011 | | try self.addLabel(.br_if, 1); // jump out of loop into outer block (finished) |
| 3012 | | try self.emitWValue(ptr); |
| 3013 | | try self.emitWValue(offset); |
| 3014 | | switch (self.arch()) { |
| 3015 | | .wasm32 => try self.addTag(.i32_add), |
| 3016 | | .wasm64 => try self.addTag(.i64_add), |
| 3017 | | else => unreachable, |
| 3018 | | } |
| 3019 | | try self.emitWValue(value); |
| 3020 | | const mem_store_op: Mir.Inst.Tag = switch (self.arch()) { |
| 3021 | | .wasm32 => .i32_store8, |
| 3022 | | .wasm64 => .i64_store8, |
| 3023 | | else => unreachable, |
| 3024 | | }; |
| 3025 | | try self.addMemArg(mem_store_op, .{ .offset = ptr.offset(), .alignment = 1 }); |
| 3026 | | try self.emitWValue(offset); |
| 3027 | | try self.addImm32(1); |
| 3028 | | switch (self.ptrSize()) { |
| 3029 | | 4 => try self.addTag(.i32_add), |
| 3030 | | 8 => try self.addTag(.i64_add), |
| 3031 | | else => unreachable, |
| 3006 | // When the length is comptime-known we do the loop at codegen, rather |
| 3007 | // than emitting a runtime loop into the binary |
| 3008 | switch (len) { |
| 3009 | .imm32, .imm64 => { |
| 3010 | const length = switch (len) { |
| 3011 | .imm32 => |val| val, |
| 3012 | .imm64 => |val| val, |
| 3013 | else => unreachable, |
| 3014 | }; |
| 3015 | |
| 3016 | var offset: u32 = 0; |
| 3017 | const base = ptr.offset(); |
| 3018 | while (offset < length) : (offset += 1) { |
| 3019 | try self.emitWValue(ptr); |
| 3020 | try self.emitWValue(value); |
| 3021 | switch (self.arch()) { |
| 3022 | .wasm32 => { |
| 3023 | try self.addMemArg(.i32_store8, .{ .offset = base + offset, .alignment = 1 }); |
| 3024 | }, |
| 3025 | .wasm64 => { |
| 3026 | try self.addMemArg(.i64_store8, .{ .offset = base + offset, .alignment = 1 }); |
| 3027 | }, |
| 3028 | else => unreachable, |
| 3029 | } |
| 3030 | } |
| 3031 | }, |
| 3032 | else => { |
| 3033 | // TODO: We should probably lower this to a call to compiler_rt |
| 3034 | // But for now, we implement it manually |
| 3035 | const offset = try self.allocLocal(Type.usize); // local for counter |
| 3036 | // outer block to jump to when loop is done |
| 3037 | try self.startBlock(.block, wasm.block_empty); |
| 3038 | try self.startBlock(.loop, wasm.block_empty); |
| 3039 | try self.emitWValue(offset); |
| 3040 | try self.emitWValue(len); |
| 3041 | switch (self.arch()) { |
| 3042 | .wasm32 => try self.addTag(.i32_eq), |
| 3043 | .wasm64 => try self.addTag(.i64_eq), |
| 3044 | else => unreachable, |
| 3045 | } |
| 3046 | try self.addLabel(.br_if, 1); // jump out of loop into outer block (finished) |
| 3047 | try self.emitWValue(ptr); |
| 3048 | try self.emitWValue(offset); |
| 3049 | switch (self.arch()) { |
| 3050 | .wasm32 => try self.addTag(.i32_add), |
| 3051 | .wasm64 => try self.addTag(.i64_add), |
| 3052 | else => unreachable, |
| 3053 | } |
| 3054 | try self.emitWValue(value); |
| 3055 | const mem_store_op: Mir.Inst.Tag = switch (self.arch()) { |
| 3056 | .wasm32 => .i32_store8, |
| 3057 | .wasm64 => .i64_store8, |
| 3058 | else => unreachable, |
| 3059 | }; |
| 3060 | try self.addMemArg(mem_store_op, .{ .offset = ptr.offset(), .alignment = 1 }); |
| 3061 | try self.emitWValue(offset); |
| 3062 | try self.addImm32(1); |
| 3063 | switch (self.arch()) { |
| 3064 | .wasm32 => try self.addTag(.i32_add), |
| 3065 | .wasm64 => try self.addTag(.i64_add), |
| 3066 | else => unreachable, |
| 3067 | } |
| 3068 | try self.addLabel(.local_set, offset.local); |
| 3069 | try self.addLabel(.br, 0); // jump to start of loop |
| 3070 | try self.endBlock(); |
| 3071 | try self.endBlock(); |
| 3072 | }, |
| 3032 | 3073 | } |
| 3033 | | try self.addLabel(.local_set, offset.local); |
| 3034 | | try self.addLabel(.br, 0); // jump to start of loop |
| 3035 | | try self.endBlock(); |
| 3036 | | try self.endBlock(); |
| 3037 | 3074 | } |
| 3038 | 3075 | |
| 3039 | 3076 | fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |