authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-03-22 15:53:43+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-22 20:16:05-07:00
log62529a291bd41eccbafeda602d7efcb4ec946939
treeab5b3672254966b07614d092812298d6bd919042
parenta4e8294c91d21e6c574bbae94e064935d90e8e95

stage2 ARM: More support for error unions


1 files changed, 84 insertions(+), 55 deletions(-)

src/arch/arm/CodeGen.zig+84-55
......@@ -1261,27 +1261,84 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {
12611261 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
12621262}
12631263
1264fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {
1265 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1266 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1267 const optional_ty = self.air.typeOfIndex(inst);
1268 const abi_size = @intCast(u32, optional_ty.abiSize(self.target.*));
1269
1270 // Optional with a zero-bit payload type is just a boolean true
1271 if (abi_size == 1) {
1272 break :result MCValue{ .immediate = 1 };
1273 } else {
1274 return self.fail("TODO implement wrap optional for {}", .{self.target.cpu.arch});
1275 }
1276 };
1277 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1278}
1279
1280/// Given an error union, returns the error
1281fn errUnionErr(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) !MCValue {
1282 const payload_ty = error_union_ty.errorUnionPayload();
1283 if (!payload_ty.hasRuntimeBits()) return error_union_mcv;
1284
1285 switch (error_union_mcv) {
1286 .register => return self.fail("TODO errUnionErr for registers", .{}),
1287 .stack_argument_offset => |off| {
1288 return MCValue{ .stack_argument_offset = off };
1289 },
1290 .stack_offset => |off| {
1291 return MCValue{ .stack_offset = off };
1292 },
1293 .memory => |addr| {
1294 return MCValue{ .memory = addr };
1295 },
1296 else => unreachable, // invalid MCValue for an error union
1297 }
1298}
1299
12641300fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void {
12651301 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
12661302 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
12671303 const error_union_ty = self.air.typeOf(ty_op.operand);
1268 const payload_ty = error_union_ty.errorUnionPayload();
12691304 const mcv = try self.resolveInst(ty_op.operand);
1270 if (!payload_ty.hasRuntimeBits()) break :result mcv;
1271
1272 return self.fail("TODO implement unwrap error union error for non-empty payloads", .{});
1305 break :result try self.errUnionErr(mcv, error_union_ty);
12731306 };
12741307 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
12751308}
12761309
1310/// Given an error union, returns the payload
1311fn errUnionPayload(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) !MCValue {
1312 const payload_ty = error_union_ty.errorUnionPayload();
1313 if (!payload_ty.hasRuntimeBits()) return MCValue.none;
1314
1315 const error_ty = error_union_ty.errorUnionSet();
1316 const error_size = @intCast(u32, error_ty.abiSize(self.target.*));
1317 const eu_align = @intCast(u32, error_union_ty.abiAlignment(self.target.*));
1318 const offset = std.mem.alignForwardGeneric(u32, error_size, eu_align);
1319
1320 // TODO optimization for small error unions: put into register
1321 switch (error_union_mcv) {
1322 .register => return self.fail("TODO errUnionPayload for registers", .{}),
1323 .stack_argument_offset => |off| {
1324 return MCValue{ .stack_argument_offset = off - offset };
1325 },
1326 .stack_offset => |off| {
1327 return MCValue{ .stack_offset = off - offset };
1328 },
1329 .memory => |addr| {
1330 return MCValue{ .memory = addr - offset };
1331 },
1332 else => unreachable, // invalid MCValue for an error union
1333 }
1334}
1335
12771336fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void {
12781337 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
12791338 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
12801339 const error_union_ty = self.air.typeOf(ty_op.operand);
1281 const payload_ty = error_union_ty.errorUnionPayload();
1282 if (!payload_ty.hasRuntimeBits()) break :result MCValue.none;
1283
1284 return self.fail("TODO implement unwrap error union payload for non-empty payloads", .{});
1340 const mcv = try self.resolveInst(ty_op.operand);
1341 break :result try self.errUnionPayload(mcv, error_union_ty);
12851342 };
12861343 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
12871344}
......@@ -1306,22 +1363,6 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {
13061363 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
13071364}
13081365
1309fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {
1310 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1311 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1312 const optional_ty = self.air.typeOfIndex(inst);
1313 const abi_size = @intCast(u32, optional_ty.abiSize(self.target.*));
1314
1315 // Optional with a zero-bit payload type is just a boolean true
1316 if (abi_size == 1) {
1317 break :result MCValue{ .immediate = 1 };
1318 } else {
1319 return self.fail("TODO implement wrap optional for {}", .{self.target.cpu.arch});
1320 }
1321 };
1322 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1323}
1324
13251366/// T to E!T
13261367fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void {
13271368 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
......@@ -1343,9 +1384,9 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {
13431384 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
13441385}
13451386
1346fn slicePtr(self: *Self, mcv: MCValue) !MCValue {
1387/// Given a slice, returns the length
1388fn slicePtr(mcv: MCValue) MCValue {
13471389 switch (mcv) {
1348 .dead, .unreach => unreachable,
13491390 .register => unreachable, // a slice doesn't fit in one register
13501391 .stack_argument_offset => |off| {
13511392 return MCValue{ .stack_argument_offset = off };
......@@ -1356,7 +1397,7 @@ fn slicePtr(self: *Self, mcv: MCValue) !MCValue {
13561397 .memory => |addr| {
13571398 return MCValue{ .memory = addr };
13581399 },
1359 else => return self.fail("TODO implement slice_ptr for {}", .{mcv}),
1400 else => unreachable, // invalid MCValue for a slice
13601401 }
13611402}
13621403
......@@ -1364,7 +1405,7 @@ fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void {
13641405 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
13651406 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
13661407 const mcv = try self.resolveInst(ty_op.operand);
1367 break :result try self.slicePtr(mcv);
1408 break :result slicePtr(mcv);
13681409 };
13691410 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
13701411}
......@@ -1444,7 +1485,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
14441485 if (index_is_register) self.register_manager.freezeRegs(&.{index_mcv.register});
14451486 defer if (index_is_register) self.register_manager.unfreezeRegs(&.{index_mcv.register});
14461487
1447 const base_mcv = try self.slicePtr(slice_mcv);
1488 const base_mcv = slicePtr(slice_mcv);
14481489
14491490 switch (elem_size) {
14501491 1, 4 => {
......@@ -1507,7 +1548,7 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void {
15071548 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
15081549 const slice_mcv = try self.resolveInst(extra.lhs);
15091550 const index_mcv = try self.resolveInst(extra.rhs);
1510 const base_mcv = try self.slicePtr(slice_mcv);
1551 const base_mcv = slicePtr(slice_mcv);
15111552
15121553 const slice_ty = self.air.typeOf(extra.lhs);
15131554
......@@ -3163,35 +3204,15 @@ fn isNonNull(self: *Self, ty: Type, operand: MCValue) !MCValue {
31633204
31643205fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
31653206 const error_type = ty.errorUnionSet();
3166 const payload_type = ty.errorUnionPayload();
3207 const error_int_type = Type.initTag(.u16);
31673208
31683209 if (!error_type.hasRuntimeBits()) {
31693210 return MCValue{ .immediate = 0 }; // always false
31703211 }
31713212
3172 if (!payload_type.hasRuntimeBits()) {
3173 if (error_type.abiSize(self.target.*) <= 4) {
3174 const reg_mcv: MCValue = switch (operand) {
3175 .register => operand,
3176 else => .{ .register = try self.copyToTmpRegister(error_type, operand) },
3177 };
3178
3179 _ = try self.addInst(.{
3180 .tag = .cmp,
3181 .data = .{ .rr_op = .{
3182 .rd = undefined,
3183 .rn = reg_mcv.register,
3184 .op = Instruction.Operand.fromU32(0).?,
3185 } },
3186 });
3187
3188 return MCValue{ .compare_flags_unsigned = .gt };
3189 } else {
3190 return self.fail("TODO isErr for errors with size > 4", .{});
3191 }
3192 } else {
3193 return self.fail("TODO isErr for non-empty payloads", .{});
3194 }
3213 const error_mcv = try self.errUnionErr(operand, ty);
3214 _ = try self.binOp(.cmp_eq, null, error_mcv, .{ .immediate = 0 }, error_int_type, error_int_type);
3215 return MCValue{ .compare_flags_unsigned = .gt };
31953216}
31963217
31973218fn isNonErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
......@@ -4044,7 +4065,15 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I
40444065 try self.genSetReg(ptr_ty, src_reg, .{ .ptr_stack_offset = off });
40454066 },
40464067 .memory => |addr| try self.genSetReg(ptr_ty, src_reg, .{ .immediate = @intCast(u32, addr) }),
4047 .stack_argument_offset => return self.fail("TODO genSetStackArgument src={}", .{mcv}),
4068 .stack_argument_offset => |off| {
4069 _ = try self.addInst(.{
4070 .tag = .ldr_ptr_stack_argument,
4071 .data = .{ .r_stack_offset = .{
4072 .rt = src_reg,
4073 .stack_offset = off,
4074 } },
4075 });
4076 },
40484077 else => unreachable,
40494078 }
40504079