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 {...@@ -1261,27 +1261,84 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {
1261 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });1261 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1262}1262}
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
1264fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void {1300fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void {
1265 const ty_op = self.air.instructions.items(.data)[inst].ty_op;1301 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1266 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {1302 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1267 const error_union_ty = self.air.typeOf(ty_op.operand);1303 const error_union_ty = self.air.typeOf(ty_op.operand);
1268 const payload_ty = error_union_ty.errorUnionPayload();
1269 const mcv = try self.resolveInst(ty_op.operand);1304 const mcv = try self.resolveInst(ty_op.operand);
1270 if (!payload_ty.hasRuntimeBits()) break :result mcv;1305 break :result try self.errUnionErr(mcv, error_union_ty);
1271
1272 return self.fail("TODO implement unwrap error union error for non-empty payloads", .{});
1273 };1306 };
1274 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });1307 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1275}1308}
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
1277fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void {1336fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void {
1278 const ty_op = self.air.instructions.items(.data)[inst].ty_op;1337 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1279 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {1338 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1280 const error_union_ty = self.air.typeOf(ty_op.operand);1339 const error_union_ty = self.air.typeOf(ty_op.operand);
1281 const payload_ty = error_union_ty.errorUnionPayload();1340 const mcv = try self.resolveInst(ty_op.operand);
1282 if (!payload_ty.hasRuntimeBits()) break :result MCValue.none;1341 break :result try self.errUnionPayload(mcv, error_union_ty);
1283
1284 return self.fail("TODO implement unwrap error union payload for non-empty payloads", .{});
1285 };1342 };
1286 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });1343 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1287}1344}
...@@ -1306,22 +1363,6 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {...@@ -1306,22 +1363,6 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {
1306 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });1363 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1307}1364}
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
1325/// T to E!T1366/// T to E!T
1326fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void {1367fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void {
1327 const ty_op = self.air.instructions.items(.data)[inst].ty_op;1368 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
...@@ -1343,9 +1384,9 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {...@@ -1343,9 +1384,9 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {
1343 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });1384 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1344}1385}
13451386
1346fn slicePtr(self: *Self, mcv: MCValue) !MCValue {1387/// Given a slice, returns the length
1388fn slicePtr(mcv: MCValue) MCValue {
1347 switch (mcv) {1389 switch (mcv) {
1348 .dead, .unreach => unreachable,
1349 .register => unreachable, // a slice doesn't fit in one register1390 .register => unreachable, // a slice doesn't fit in one register
1350 .stack_argument_offset => |off| {1391 .stack_argument_offset => |off| {
1351 return MCValue{ .stack_argument_offset = off };1392 return MCValue{ .stack_argument_offset = off };
...@@ -1356,7 +1397,7 @@ fn slicePtr(self: *Self, mcv: MCValue) !MCValue {...@@ -1356,7 +1397,7 @@ fn slicePtr(self: *Self, mcv: MCValue) !MCValue {
1356 .memory => |addr| {1397 .memory => |addr| {
1357 return MCValue{ .memory = addr };1398 return MCValue{ .memory = addr };
1358 },1399 },
1359 else => return self.fail("TODO implement slice_ptr for {}", .{mcv}),1400 else => unreachable, // invalid MCValue for a slice
1360 }1401 }
1361}1402}
13621403
...@@ -1364,7 +1405,7 @@ fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -1364,7 +1405,7 @@ fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void {
1364 const ty_op = self.air.instructions.items(.data)[inst].ty_op;1405 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1365 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {1406 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1366 const mcv = try self.resolveInst(ty_op.operand);1407 const mcv = try self.resolveInst(ty_op.operand);
1367 break :result try self.slicePtr(mcv);1408 break :result slicePtr(mcv);
1368 };1409 };
1369 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });1410 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1370}1411}
...@@ -1444,7 +1485,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -1444,7 +1485,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
1444 if (index_is_register) self.register_manager.freezeRegs(&.{index_mcv.register});1485 if (index_is_register) self.register_manager.freezeRegs(&.{index_mcv.register});
1445 defer if (index_is_register) self.register_manager.unfreezeRegs(&.{index_mcv.register});1486 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
1449 switch (elem_size) {1490 switch (elem_size) {
1450 1, 4 => {1491 1, 4 => {
...@@ -1507,7 +1548,7 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -1507,7 +1548,7 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void {
1507 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {1548 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1508 const slice_mcv = try self.resolveInst(extra.lhs);1549 const slice_mcv = try self.resolveInst(extra.lhs);
1509 const index_mcv = try self.resolveInst(extra.rhs);1550 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
1512 const slice_ty = self.air.typeOf(extra.lhs);1553 const slice_ty = self.air.typeOf(extra.lhs);
15131554
...@@ -3163,35 +3204,15 @@ fn isNonNull(self: *Self, ty: Type, operand: MCValue) !MCValue {...@@ -3163,35 +3204,15 @@ fn isNonNull(self: *Self, ty: Type, operand: MCValue) !MCValue {
31633204
3164fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {3205fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
3165 const error_type = ty.errorUnionSet();3206 const error_type = ty.errorUnionSet();
3166 const payload_type = ty.errorUnionPayload();3207 const error_int_type = Type.initTag(.u16);
31673208
3168 if (!error_type.hasRuntimeBits()) {3209 if (!error_type.hasRuntimeBits()) {
3169 return MCValue{ .immediate = 0 }; // always false3210 return MCValue{ .immediate = 0 }; // always false
3170 }3211 }
31713212
3172 if (!payload_type.hasRuntimeBits()) {3213 const error_mcv = try self.errUnionErr(operand, ty);
3173 if (error_type.abiSize(self.target.*) <= 4) {3214 _ = try self.binOp(.cmp_eq, null, error_mcv, .{ .immediate = 0 }, error_int_type, error_int_type);
3174 const reg_mcv: MCValue = switch (operand) {3215 return MCValue{ .compare_flags_unsigned = .gt };
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 }
3195}3216}
31963217
3197fn isNonErr(self: *Self, ty: Type, operand: MCValue) !MCValue {3218fn isNonErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
...@@ -4044,7 +4065,15 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I...@@ -4044,7 +4065,15 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I
4044 try self.genSetReg(ptr_ty, src_reg, .{ .ptr_stack_offset = off });4065 try self.genSetReg(ptr_ty, src_reg, .{ .ptr_stack_offset = off });
4045 },4066 },
4046 .memory => |addr| try self.genSetReg(ptr_ty, src_reg, .{ .immediate = @intCast(u32, addr) }),4067 .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 },
4048 else => unreachable,4077 else => unreachable,
4049 }4078 }
40504079