authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-02-01 18:57:51+01:00
committergravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-02-14 22:09:39+01:00
log0d16e908fbb93cdaee80bc2514f76a09736bfa04
tree0699ae47b9776188d4e7473917e24964e674dcf6
parent7b938767bb18535a870d0460c9f4d9e3d93ab053
signaturelock-open Commit is signed but in an unrecognized format.

stage2 AArch64: implement is_err/is_non_err for simple error unions


1 files changed, 73 insertions(+), 20 deletions(-)

src/arch/aarch64/CodeGen.zig+73-20
...@@ -1104,7 +1104,13 @@ fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void {...@@ -1104,7 +1104,13 @@ fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void {
11041104
1105fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void {1105fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void {
1106 const ty_op = self.air.instructions.items(.data)[inst].ty_op;1106 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1107 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement unwrap error union payload for {}", .{self.target.cpu.arch});1107 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1108 const error_union_ty = self.air.typeOf(ty_op.operand);
1109 const payload_ty = error_union_ty.errorUnionPayload();
1110 if (!payload_ty.hasRuntimeBits()) break :result MCValue.none;
1111
1112 return self.fail("TODO implement unwrap error union payload for non-empty payloads", .{});
1113 };
1108 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });1114 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1109}1115}
11101116
...@@ -2008,18 +2014,52 @@ fn isNonNull(self: *Self, operand: MCValue) !MCValue {...@@ -2008,18 +2014,52 @@ fn isNonNull(self: *Self, operand: MCValue) !MCValue {
2008 return self.fail("TODO call isNull and invert the result", .{});2014 return self.fail("TODO call isNull and invert the result", .{});
2009}2015}
20102016
2011fn isErr(self: *Self, operand: MCValue) !MCValue {2017fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
2012 _ = operand;2018 _ = operand;
2013 // Here you can specialize this instruction if it makes sense to, otherwise the default2019
2014 // will call isNonNull and invert the result.2020 const error_type = ty.errorUnionSet();
2015 return self.fail("TODO call isNonErr and invert the result", .{});2021 const payload_type = ty.errorUnionPayload();
2022
2023 if (!error_type.hasRuntimeBits()) {
2024 return MCValue{ .immediate = 0 }; // always false
2025 } else if (!payload_type.hasRuntimeBits()) {
2026 if (error_type.abiSize(self.target.*) <= 8) {
2027 const reg_mcv: MCValue = switch (operand) {
2028 .register => operand,
2029 else => .{ .register = try self.copyToTmpRegister(error_type, operand) },
2030 };
2031
2032 _ = try self.addInst(.{
2033 .tag = .cmp_immediate,
2034 .data = .{ .rr_imm12_sh = .{
2035 .rd = .xzr,
2036 .rn = reg_mcv.register,
2037 .imm12 = 0,
2038 } },
2039 });
2040
2041 return MCValue{ .compare_flags_unsigned = .gt };
2042 } else {
2043 return self.fail("TODO isErr for errors with size > 8", .{});
2044 }
2045 } else {
2046 return self.fail("TODO isErr for non-empty payloads", .{});
2047 }
2016}2048}
20172049
2018fn isNonErr(self: *Self, operand: MCValue) !MCValue {2050fn isNonErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
2019 _ = operand;2051 const is_err_result = try self.isErr(ty, operand);
2020 // Here you can specialize this instruction if it makes sense to, otherwise the default2052 switch (is_err_result) {
2021 // will call isNull and invert the result.2053 .compare_flags_unsigned => |op| {
2022 return self.fail("TODO call isErr and invert the result", .{});2054 assert(op == .gt);
2055 return MCValue{ .compare_flags_unsigned = .lte };
2056 },
2057 .immediate => |imm| {
2058 assert(imm == 0);
2059 return MCValue{ .immediate = 1 };
2060 },
2061 else => unreachable,
2062 }
2023}2063}
20242064
2025fn airIsNull(self: *Self, inst: Air.Inst.Index) !void {2065fn airIsNull(self: *Self, inst: Air.Inst.Index) !void {
...@@ -2080,7 +2120,8 @@ fn airIsErr(self: *Self, inst: Air.Inst.Index) !void {...@@ -2080,7 +2120,8 @@ fn airIsErr(self: *Self, inst: Air.Inst.Index) !void {
2080 const un_op = self.air.instructions.items(.data)[inst].un_op;2120 const un_op = self.air.instructions.items(.data)[inst].un_op;
2081 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {2121 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
2082 const operand = try self.resolveInst(un_op);2122 const operand = try self.resolveInst(un_op);
2083 break :result try self.isErr(operand);2123 const ty = self.air.typeOf(un_op);
2124 break :result try self.isErr(ty, operand);
2084 };2125 };
2085 return self.finishAir(inst, result, .{ un_op, .none, .none });2126 return self.finishAir(inst, result, .{ un_op, .none, .none });
2086}2127}
...@@ -2089,6 +2130,7 @@ fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -2089,6 +2130,7 @@ fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void {
2089 const un_op = self.air.instructions.items(.data)[inst].un_op;2130 const un_op = self.air.instructions.items(.data)[inst].un_op;
2090 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {2131 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
2091 const operand_ptr = try self.resolveInst(un_op);2132 const operand_ptr = try self.resolveInst(un_op);
2133 const ptr_ty = self.air.typeOf(un_op);
2092 const operand: MCValue = blk: {2134 const operand: MCValue = blk: {
2093 if (self.reuseOperand(inst, un_op, 0, operand_ptr)) {2135 if (self.reuseOperand(inst, un_op, 0, operand_ptr)) {
2094 // The MCValue that holds the pointer can be re-used as the value.2136 // The MCValue that holds the pointer can be re-used as the value.
...@@ -2098,7 +2140,7 @@ fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -2098,7 +2140,7 @@ fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void {
2098 }2140 }
2099 };2141 };
2100 try self.load(operand, operand_ptr, self.air.typeOf(un_op));2142 try self.load(operand, operand_ptr, self.air.typeOf(un_op));
2101 break :result try self.isErr(operand);2143 break :result try self.isErr(ptr_ty.elemType(), operand);
2102 };2144 };
2103 return self.finishAir(inst, result, .{ un_op, .none, .none });2145 return self.finishAir(inst, result, .{ un_op, .none, .none });
2104}2146}
...@@ -2107,7 +2149,8 @@ fn airIsNonErr(self: *Self, inst: Air.Inst.Index) !void {...@@ -2107,7 +2149,8 @@ fn airIsNonErr(self: *Self, inst: Air.Inst.Index) !void {
2107 const un_op = self.air.instructions.items(.data)[inst].un_op;2149 const un_op = self.air.instructions.items(.data)[inst].un_op;
2108 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {2150 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
2109 const operand = try self.resolveInst(un_op);2151 const operand = try self.resolveInst(un_op);
2110 break :result try self.isNonErr(operand);2152 const ty = self.air.typeOf(un_op);
2153 break :result try self.isNonErr(ty, operand);
2111 };2154 };
2112 return self.finishAir(inst, result, .{ un_op, .none, .none });2155 return self.finishAir(inst, result, .{ un_op, .none, .none });
2113}2156}
...@@ -2116,6 +2159,7 @@ fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -2116,6 +2159,7 @@ fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void {
2116 const un_op = self.air.instructions.items(.data)[inst].un_op;2159 const un_op = self.air.instructions.items(.data)[inst].un_op;
2117 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {2160 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
2118 const operand_ptr = try self.resolveInst(un_op);2161 const operand_ptr = try self.resolveInst(un_op);
2162 const ptr_ty = self.air.typeOf(un_op);
2119 const operand: MCValue = blk: {2163 const operand: MCValue = blk: {
2120 if (self.reuseOperand(inst, un_op, 0, operand_ptr)) {2164 if (self.reuseOperand(inst, un_op, 0, operand_ptr)) {
2121 // The MCValue that holds the pointer can be re-used as the value.2165 // The MCValue that holds the pointer can be re-used as the value.
...@@ -2125,7 +2169,7 @@ fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -2125,7 +2169,7 @@ fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void {
2125 }2169 }
2126 };2170 };
2127 try self.load(operand, operand_ptr, self.air.typeOf(un_op));2171 try self.load(operand, operand_ptr, self.air.typeOf(un_op));
2128 break :result try self.isNonErr(operand);2172 break :result try self.isNonErr(ptr_ty.elemType(), operand);
2129 };2173 };
2130 return self.finishAir(inst, result, .{ un_op, .none, .none });2174 return self.finishAir(inst, result, .{ un_op, .none, .none });
2131}2175}
...@@ -2864,14 +2908,23 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {...@@ -2864,14 +2908,23 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
2864 .ErrorUnion => {2908 .ErrorUnion => {
2865 const error_type = typed_value.ty.errorUnionSet();2909 const error_type = typed_value.ty.errorUnionSet();
2866 const payload_type = typed_value.ty.errorUnionPayload();2910 const payload_type = typed_value.ty.errorUnionPayload();
2867 const sub_val = typed_value.val.castTag(.eu_payload).?.data;
28682911
2869 if (!payload_type.hasRuntimeBits()) {2912 if (typed_value.val.castTag(.eu_payload)) |pl| {
2870 // We use the error type directly as the type.2913 if (!payload_type.hasRuntimeBits()) {
2871 return self.genTypedValue(.{ .ty = error_type, .val = sub_val });2914 // We use the error type directly as the type.
2872 }2915 return MCValue{ .immediate = 0 };
2916 }
28732917
2874 return self.fail("TODO implement error union const of type '{}'", .{typed_value.ty});2918 _ = pl;
2919 return self.fail("TODO implement error union const of type '{}' (non-error)", .{typed_value.ty});
2920 } else {
2921 if (!payload_type.hasRuntimeBits()) {
2922 // We use the error type directly as the type.
2923 return self.genTypedValue(.{ .ty = error_type, .val = typed_value.val });
2924 }
2925
2926 return self.fail("TODO implement error union const of type '{}' (error)", .{typed_value.ty});
2927 }
2875 },2928 },
2876 else => return self.fail("TODO implement const of type '{}'", .{typed_value.ty}),2929 else => return self.fail("TODO implement const of type '{}'", .{typed_value.ty}),
2877 }2930 }