| ... | @@ -415,9 +415,14 @@ fn gen(self: *Self) InnerError!void { | ... | @@ -415,9 +415,14 @@ fn gen(self: *Self) InnerError!void { |
| 415 | | 415 | |
| 416 | try self.genBody(self.air.getMainBody()); | 416 | try self.genBody(self.air.getMainBody()); |
| 417 | | 417 | |
| 418 | if (self.exitlude_jump_relocs.items.len == 1) { | 418 | // TODO can single exitlude jump reloc be elided? What if it is not at the end of the code? |
| 419 | self.mir_instructions.len -= 1; | 419 | // Example: |
| 420 | } else for (self.exitlude_jump_relocs.items) |jmp_reloc| { | 420 | // pub fn main() void { |
| | 421 | // maybeErr() catch return; |
| | 422 | // unreachable; |
| | 423 | // } |
| | 424 | // Eliding the reloc will cause a miscompilation in this case. |
| | 425 | for (self.exitlude_jump_relocs.items) |jmp_reloc| { |
| 421 | self.mir_instructions.items(.data)[jmp_reloc].inst = @intCast(u32, self.mir_instructions.len); | 426 | self.mir_instructions.items(.data)[jmp_reloc].inst = @intCast(u32, self.mir_instructions.len); |
| 422 | } | 427 | } |
| 423 | | 428 | |
| ... | @@ -1180,19 +1185,24 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1180,19 +1185,24 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { |
| 1180 | | 1185 | |
| 1181 | fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void { | 1186 | fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void { |
| 1182 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 1187 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1183 | const result: MCValue = if (self.liveness.isUnused(inst)) | 1188 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1184 | .dead | 1189 | const err_union_ty = self.air.typeOf(ty_op.operand); |
| 1185 | else | 1190 | const payload_ty = err_union_ty.errorUnionPayload(); |
| 1186 | return self.fail("TODO implement unwrap error union error for {}", .{self.target.cpu.arch}); | 1191 | const mcv = try self.resolveInst(ty_op.operand); |
| | 1192 | if (!payload_ty.hasCodeGenBits()) break :result mcv; |
| | 1193 | return self.fail("TODO implement unwrap error union error for non-empty payloads", .{}); |
| | 1194 | }; |
| 1187 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 1195 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1188 | } | 1196 | } |
| 1189 | | 1197 | |
| 1190 | fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void { | 1198 | fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 1191 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 1199 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1192 | const result: MCValue = if (self.liveness.isUnused(inst)) | 1200 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1193 | .dead | 1201 | const err_union_ty = self.air.typeOf(ty_op.operand); |
| 1194 | else | 1202 | const payload_ty = err_union_ty.errorUnionPayload(); |
| 1195 | return self.fail("TODO implement unwrap error union payload for {}", .{self.target.cpu.arch}); | 1203 | if (!payload_ty.hasCodeGenBits()) break :result MCValue.none; |
| | 1204 | return self.fail("TODO implement unwrap error union payload for non-empty payloads", .{}); |
| | 1205 | }; |
| 1196 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 1206 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1197 | } | 1207 | } |
| 1198 | | 1208 | |
| ... | @@ -2396,19 +2406,35 @@ fn isNonNull(self: *Self, ty: Type, operand: MCValue) !MCValue { | ... | @@ -2396,19 +2406,35 @@ fn isNonNull(self: *Self, ty: Type, operand: MCValue) !MCValue { |
| 2396 | } | 2406 | } |
| 2397 | | 2407 | |
| 2398 | fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue { | 2408 | fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue { |
| 2399 | _ = ty; | 2409 | const err_type = ty.errorUnionSet(); |
| 2400 | _ = operand; | 2410 | const payload_type = ty.errorUnionPayload(); |
| 2401 | // Here you can specialize this instruction if it makes sense to, otherwise the default | 2411 | if (!err_type.hasCodeGenBits()) { |
| 2402 | // will call isNonErr and invert the result. | 2412 | return MCValue{ .immediate = 0 }; // always false |
| 2403 | return self.fail("TODO call isNonErr and invert the result", .{}); | 2413 | } else if (!payload_type.hasCodeGenBits()) { |
| | 2414 | if (err_type.abiSize(self.target.*) <= 8) { |
| | 2415 | try self.genBinMathOpMir(.cmp, err_type, operand, MCValue{ .immediate = 0 }); |
| | 2416 | return MCValue{ .compare_flags_unsigned = .gt }; |
| | 2417 | } else { |
| | 2418 | return self.fail("TODO isErr for errors with size larger than register size", .{}); |
| | 2419 | } |
| | 2420 | } else { |
| | 2421 | return self.fail("TODO isErr for non-empty payloads", .{}); |
| | 2422 | } |
| 2404 | } | 2423 | } |
| 2405 | | 2424 | |
| 2406 | fn isNonErr(self: *Self, ty: Type, operand: MCValue) !MCValue { | 2425 | fn isNonErr(self: *Self, ty: Type, operand: MCValue) !MCValue { |
| 2407 | _ = ty; | 2426 | const is_err_res = try self.isErr(ty, operand); |
| 2408 | _ = operand; | 2427 | switch (is_err_res) { |
| 2409 | // Here you can specialize this instruction if it makes sense to, otherwise the default | 2428 | .compare_flags_unsigned => |op| { |
| 2410 | // will call isErr and invert the result. | 2429 | assert(op == .gt); |
| 2411 | return self.fail("TODO call isErr and invert the result", .{}); | 2430 | return MCValue{ .compare_flags_unsigned = .lte }; |
| | 2431 | }, |
| | 2432 | .immediate => |imm| { |
| | 2433 | assert(imm == 0); |
| | 2434 | return MCValue{ .immediate = 1 }; |
| | 2435 | }, |
| | 2436 | else => unreachable, |
| | 2437 | } |
| 2412 | } | 2438 | } |
| 2413 | | 2439 | |
| 2414 | fn airIsNull(self: *Self, inst: Air.Inst.Index) !void { | 2440 | fn airIsNull(self: *Self, inst: Air.Inst.Index) !void { |
| ... | @@ -3435,31 +3461,32 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { | ... | @@ -3435,31 +3461,32 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { |
| 3435 | } | 3461 | } |
| 3436 | }, | 3462 | }, |
| 3437 | .ErrorSet => { | 3463 | .ErrorSet => { |
| 3438 | switch (typed_value.val.tag()) { | 3464 | const err_name = typed_value.val.castTag(.@"error").?.data.name; |
| 3439 | .@"error" => { | 3465 | const module = self.bin_file.options.module.?; |
| 3440 | const err_name = typed_value.val.castTag(.@"error").?.data.name; | 3466 | const global_error_set = module.global_error_set; |
| 3441 | const module = self.bin_file.options.module.?; | 3467 | const error_index = global_error_set.get(err_name).?; |
| 3442 | const global_error_set = module.global_error_set; | 3468 | return MCValue{ .immediate = error_index }; |
| 3443 | const error_index = global_error_set.get(err_name).?; | | |
| 3444 | return MCValue{ .immediate = error_index }; | | |
| 3445 | }, | | |
| 3446 | else => { | | |
| 3447 | // In this case we are rendering an error union which has a 0 bits payload. | | |
| 3448 | return MCValue{ .immediate = 0 }; | | |
| 3449 | }, | | |
| 3450 | } | | |
| 3451 | }, | 3469 | }, |
| 3452 | .ErrorUnion => { | 3470 | .ErrorUnion => { |
| 3453 | const error_type = typed_value.ty.errorUnionSet(); | 3471 | const error_type = typed_value.ty.errorUnionSet(); |
| 3454 | const payload_type = typed_value.ty.errorUnionPayload(); | 3472 | const payload_type = typed_value.ty.errorUnionPayload(); |
| 3455 | const sub_val = typed_value.val.castTag(.eu_payload).?.data; | | |
| 3456 | | 3473 | |
| 3457 | if (!payload_type.hasCodeGenBits()) { | 3474 | if (typed_value.val.castTag(.eu_payload)) |pl| { |
| 3458 | // We use the error type directly as the type. | 3475 | if (!payload_type.hasCodeGenBits()) { |
| 3459 | return self.genTypedValue(.{ .ty = error_type, .val = sub_val }); | 3476 | // We use the error type directly as the type. |
| | 3477 | return MCValue{ .immediate = 0 }; |
| | 3478 | } |
| | 3479 | |
| | 3480 | _ = pl; |
| | 3481 | return self.fail("TODO implement error union const of type '{}' (non-error)", .{typed_value.ty}); |
| | 3482 | } else { |
| | 3483 | if (!payload_type.hasCodeGenBits()) { |
| | 3484 | // We use the error type directly as the type. |
| | 3485 | return self.genTypedValue(.{ .ty = error_type, .val = typed_value.val }); |
| | 3486 | } |
| 3460 | } | 3487 | } |
| 3461 | | 3488 | |
| 3462 | return self.fail("TODO implement error union const of type '{}'", .{typed_value.ty}); | 3489 | return self.fail("TODO implement error union const of type '{}' (error)", .{typed_value.ty}); |
| 3463 | }, | 3490 | }, |
| 3464 | else => return self.fail("TODO implement const of type '{}'", .{typed_value.ty}), | 3491 | else => return self.fail("TODO implement const of type '{}'", .{typed_value.ty}), |
| 3465 | } | 3492 | } |