| ... | @@ -1641,12 +1641,13 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro | ... | @@ -1641,12 +1641,13 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro |
| 1641 | } | 1641 | } |
| 1642 | }, | 1642 | }, |
| 1643 | .Struct, .Array => { | 1643 | .Struct, .Array => { |
| 1644 | if (rhs == .constant) { | 1644 | const final_rhs = if (rhs == .constant) blk: { |
| | 1645 | const tmp = try self.allocLocal(Type.usize); |
| 1645 | try self.emitWValue(rhs); | 1646 | try self.emitWValue(rhs); |
| 1646 | try self.addLabel(.local_set, lhs.local); | 1647 | try self.addLabel(.local_set, tmp.local); |
| 1647 | return; | 1648 | break :blk tmp; |
| 1648 | } | 1649 | } else rhs; |
| 1649 | return try self.memCopy(ty, lhs, rhs); | 1650 | return try self.memCopy(ty, lhs, final_rhs); |
| 1650 | }, | 1651 | }, |
| 1651 | .Pointer => { | 1652 | .Pointer => { |
| 1652 | if (ty.isSlice() and rhs == .constant) { | 1653 | if (ty.isSlice() and rhs == .constant) { |
| ... | @@ -2267,9 +2268,6 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: std.math.CompareOperator) Inner | ... | @@ -2267,9 +2268,6 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: std.math.CompareOperator) Inner |
| 2267 | const rhs = self.resolveInst(bin_op.rhs); | 2268 | const rhs = self.resolveInst(bin_op.rhs); |
| 2268 | const operand_ty = self.air.typeOf(bin_op.lhs); | 2269 | const operand_ty = self.air.typeOf(bin_op.lhs); |
| 2269 | | 2270 | |
| 2270 | try self.emitWValue(lhs); | | |
| 2271 | try self.emitWValue(rhs); | | |
| 2272 | | | |
| 2273 | if (operand_ty.zigTypeTag() == .Optional and !operand_ty.isPtrLikeOptional()) { | 2271 | if (operand_ty.zigTypeTag() == .Optional and !operand_ty.isPtrLikeOptional()) { |
| 2274 | var buf: Type.Payload.ElemType = undefined; | 2272 | var buf: Type.Payload.ElemType = undefined; |
| 2275 | const payload_ty = operand_ty.optionalChild(&buf); | 2273 | const payload_ty = operand_ty.optionalChild(&buf); |
| ... | @@ -2277,10 +2275,13 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: std.math.CompareOperator) Inner | ... | @@ -2277,10 +2275,13 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: std.math.CompareOperator) Inner |
| 2277 | // When we hit this case, we must check the value of optionals | 2275 | // When we hit this case, we must check the value of optionals |
| 2278 | // that are not pointers. This means first checking against non-null for | 2276 | // that are not pointers. This means first checking against non-null for |
| 2279 | // both lhs and rhs, as well as checking the payload are matching of lhs and rhs | 2277 | // both lhs and rhs, as well as checking the payload are matching of lhs and rhs |
| 2280 | return self.fail("TODO: Implement airCmp for comparing optionals", .{}); | 2278 | return self.cmpOptionals(lhs, rhs, operand_ty, op); |
| 2281 | } | 2279 | } |
| 2282 | } | 2280 | } |
| 2283 | | 2281 | |
| | 2282 | try self.emitWValue(lhs); |
| | 2283 | try self.emitWValue(rhs); |
| | 2284 | |
| 2284 | const signedness: std.builtin.Signedness = blk: { | 2285 | const signedness: std.builtin.Signedness = blk: { |
| 2285 | // by default we tell the operand type is unsigned (i.e. bools and enum values) | 2286 | // by default we tell the operand type is unsigned (i.e. bools and enum values) |
| 2286 | if (operand_ty.zigTypeTag() != .Int) break :blk .unsigned; | 2287 | if (operand_ty.zigTypeTag() != .Int) break :blk .unsigned; |
| ... | @@ -2705,12 +2706,16 @@ fn airIsNull(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode, op_kind: en | ... | @@ -2705,12 +2706,16 @@ fn airIsNull(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode, op_kind: en |
| 2705 | | 2706 | |
| 2706 | const op_ty = self.air.typeOf(un_op); | 2707 | const op_ty = self.air.typeOf(un_op); |
| 2707 | const optional_ty = if (op_kind == .ptr) op_ty.childType() else op_ty; | 2708 | const optional_ty = if (op_kind == .ptr) op_ty.childType() else op_ty; |
| | 2709 | return self.isNull(operand, optional_ty, opcode); |
| | 2710 | } |
| | 2711 | |
| | 2712 | fn isNull(self: *Self, operand: WValue, optional_ty: Type, opcode: wasm.Opcode) InnerError!WValue { |
| 2708 | try self.emitWValue(operand); | 2713 | try self.emitWValue(operand); |
| 2709 | if (!optional_ty.isPtrLikeOptional()) { | 2714 | if (!optional_ty.isPtrLikeOptional()) { |
| 2710 | var buf: Type.Payload.ElemType = undefined; | 2715 | var buf: Type.Payload.ElemType = undefined; |
| 2711 | const payload_ty = optional_ty.optionalChild(&buf); | 2716 | const payload_ty = optional_ty.optionalChild(&buf); |
| 2712 | // When payload is zero-bits, we can treat operand as a value, rather than a | 2717 | // When payload is zero-bits, we can treat operand as a value, rather than |
| 2713 | // stack value | 2718 | // a pointer to the stack value |
| 2714 | if (payload_ty.hasCodeGenBits()) { | 2719 | if (payload_ty.hasCodeGenBits()) { |
| 2715 | try self.addMemArg(.i32_load8_u, .{ .offset = 0, .alignment = 1 }); | 2720 | try self.addMemArg(.i32_load8_u, .{ .offset = 0, .alignment = 1 }); |
| 2716 | } | 2721 | } |
| ... | @@ -3205,3 +3210,44 @@ fn airFloatToInt(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -3205,3 +3210,44 @@ fn airFloatToInt(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 3205 | try self.addLabel(.local_set, result.local); | 3210 | try self.addLabel(.local_set, result.local); |
| 3206 | return result; | 3211 | return result; |
| 3207 | } | 3212 | } |
| | 3213 | |
| | 3214 | fn cmpOptionals(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.math.CompareOperator) InnerError!WValue { |
| | 3215 | assert(operand_ty.hasCodeGenBits()); |
| | 3216 | assert(op == .eq or op == .neq); |
| | 3217 | var buf: Type.Payload.ElemType = undefined; |
| | 3218 | const payload_ty = operand_ty.optionalChild(&buf); |
| | 3219 | const offset = @intCast(u32, operand_ty.abiSize(self.target) - payload_ty.abiSize(self.target)); |
| | 3220 | |
| | 3221 | const lhs_is_null = try self.isNull(lhs, operand_ty, .i32_eq); |
| | 3222 | const rhs_is_null = try self.isNull(rhs, operand_ty, .i32_eq); |
| | 3223 | |
| | 3224 | // We store the final result in here that will be validated |
| | 3225 | // if the optional is truly equal. |
| | 3226 | const result = try self.allocLocal(Type.initTag(.i32)); |
| | 3227 | |
| | 3228 | try self.startBlock(.block, wasm.block_empty); |
| | 3229 | try self.emitWValue(lhs_is_null); |
| | 3230 | try self.emitWValue(rhs_is_null); |
| | 3231 | try self.addTag(.i32_ne); // inverse so we can exit early |
| | 3232 | try self.addLabel(.br_if, 0); |
| | 3233 | |
| | 3234 | const lhs_pl = try self.load(lhs, payload_ty, offset); |
| | 3235 | const rhs_pl = try self.load(rhs, payload_ty, offset); |
| | 3236 | |
| | 3237 | try self.emitWValue(lhs_pl); |
| | 3238 | try self.emitWValue(rhs_pl); |
| | 3239 | const opcode = buildOpcode(.{ .op = .ne, .valtype1 = try self.typeToValtype(payload_ty) }); |
| | 3240 | try self.addTag(Mir.Inst.Tag.fromOpcode(opcode)); |
| | 3241 | try self.addLabel(.br_if, 0); |
| | 3242 | |
| | 3243 | try self.addImm32(1); |
| | 3244 | try self.addLabel(.local_set, result.local); |
| | 3245 | try self.endBlock(); |
| | 3246 | |
| | 3247 | const is_equal = try self.allocLocal(Type.initTag(.i32)); |
| | 3248 | try self.emitWValue(result); |
| | 3249 | try self.addImm32(0); |
| | 3250 | try self.addTag(if (op == .eq) .i32_ne else .i32_eq); |
| | 3251 | try self.addLabel(.local_set, is_equal.local); |
| | 3252 | return is_equal; |
| | 3253 | } |