authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-03-13 18:43:18+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-03-13 18:43:18+01:00
logbb859a0be7860a544aca1543cfd724435a24e380
tree0904f7a6332232ea8970e8412063243737424365
parent76bceb240d837d859378e01cc5a40b00cb6aacdb
parentb74cd902c6abf46644329409dae493335a1708bc
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #11150 from joachimschmidt557/stage2-aarch64

stage2 AArch64: misc improvements

13 files changed, 348 insertions(+), 106 deletions(-)

src/arch/aarch64/CodeGen.zig+137-75
...@@ -85,6 +85,8 @@ blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, BlockData) = .{},...@@ -85,6 +85,8 @@ blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, BlockData) = .{},
85register_manager: RegisterManager = .{},85register_manager: RegisterManager = .{},
86/// Maps offset to what is stored there.86/// Maps offset to what is stored there.
87stack: std.AutoHashMapUnmanaged(u32, StackAllocation) = .{},87stack: std.AutoHashMapUnmanaged(u32, StackAllocation) = .{},
88/// Tracks the current instruction allocated to the compare flags
89compare_flags_inst: ?Air.Inst.Index = null,
8890
89/// Offset from the stack base, representing the end of the stack frame.91/// Offset from the stack base, representing the end of the stack frame.
90max_end_stack: u32 = 0,92max_end_stack: u32 = 0,
...@@ -536,12 +538,12 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -536,12 +538,12 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
536 .sub, .ptr_sub => try self.airBinOp(inst),538 .sub, .ptr_sub => try self.airBinOp(inst),
537 .subwrap => try self.airSubWrap(inst),539 .subwrap => try self.airSubWrap(inst),
538 .sub_sat => try self.airSubSat(inst),540 .sub_sat => try self.airSubSat(inst),
539 .mul => try self.airMul(inst),541 .mul => try self.airBinOp(inst),
540 .mulwrap => try self.airMulWrap(inst),542 .mulwrap => try self.airMulWrap(inst),
541 .mul_sat => try self.airMulSat(inst),543 .mul_sat => try self.airMulSat(inst),
542 .rem => try self.airRem(inst),544 .rem => try self.airRem(inst),
543 .mod => try self.airMod(inst),545 .mod => try self.airMod(inst),
544 .shl, .shl_exact => try self.airShl(inst),546 .shl, .shl_exact => try self.airBinOp(inst),
545 .shl_sat => try self.airShlSat(inst),547 .shl_sat => try self.airShlSat(inst),
546 .min => try self.airMin(inst),548 .min => try self.airMin(inst),
547 .max => try self.airMax(inst),549 .max => try self.airMax(inst),
...@@ -581,7 +583,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -581,7 +583,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
581 .bit_and => try self.airBinOp(inst),583 .bit_and => try self.airBinOp(inst),
582 .bit_or => try self.airBinOp(inst),584 .bit_or => try self.airBinOp(inst),
583 .xor => try self.airBinOp(inst),585 .xor => try self.airBinOp(inst),
584 .shr, .shr_exact => try self.airShr(inst),586 .shr, .shr_exact => try self.airBinOp(inst),
585587
586 .alloc => try self.airAlloc(inst),588 .alloc => try self.airAlloc(inst),
587 .ret_ptr => try self.airRetPtr(inst),589 .ret_ptr => try self.airRetPtr(inst),
...@@ -722,6 +724,9 @@ fn processDeath(self: *Self, inst: Air.Inst.Index) void {...@@ -722,6 +724,9 @@ fn processDeath(self: *Self, inst: Air.Inst.Index) void {
722 const canon_reg = toCanonicalReg(reg);724 const canon_reg = toCanonicalReg(reg);
723 self.register_manager.freeReg(canon_reg);725 self.register_manager.freeReg(canon_reg);
724 },726 },
727 .compare_flags_signed, .compare_flags_unsigned => {
728 self.compare_flags_inst = null;
729 },
725 else => {}, // TODO process stack allocation death730 else => {}, // TODO process stack allocation death
726 }731 }
727}732}
...@@ -815,7 +820,9 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 {...@@ -815,7 +820,9 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 {
815 const elem_ty = self.air.typeOfIndex(inst).elemType();820 const elem_ty = self.air.typeOfIndex(inst).elemType();
816821
817 if (!elem_ty.hasRuntimeBits()) {822 if (!elem_ty.hasRuntimeBits()) {
818 return self.allocMem(inst, @sizeOf(usize), @alignOf(usize));823 // As this stack item will never be dereferenced at runtime,
824 // return the current stack offset
825 return self.next_stack_offset;
819 }826 }
820827
821 const abi_size = math.cast(u32, elem_ty.abiSize(self.target.*)) catch {828 const abi_size = math.cast(u32, elem_ty.abiSize(self.target.*)) catch {
...@@ -857,6 +864,24 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void...@@ -857,6 +864,24 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void
857 try self.genSetStack(self.air.typeOfIndex(inst), stack_mcv.stack_offset, reg_mcv);864 try self.genSetStack(self.air.typeOfIndex(inst), stack_mcv.stack_offset, reg_mcv);
858}865}
859866
867/// Save the current instruction stored in the compare flags if
868/// occupied
869fn spillCompareFlagsIfOccupied(self: *Self) !void {
870 if (self.compare_flags_inst) |inst_to_save| {
871 const mcv = self.getResolvedInstValue(inst_to_save);
872 assert(mcv == .compare_flags_signed or mcv == .compare_flags_unsigned);
873
874 const new_mcv = try self.allocRegOrMem(inst_to_save, true);
875 try self.setRegOrMem(self.air.typeOfIndex(inst_to_save), new_mcv, mcv);
876 log.debug("spilling {d} to mcv {any}", .{ inst_to_save, new_mcv });
877
878 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
879 try branch.inst_table.put(self.gpa, inst_to_save, new_mcv);
880
881 self.compare_flags_inst = null;
882 }
883}
884
860/// Copies a value to a register without tracking the register. The register is not considered885/// Copies a value to a register without tracking the register. The register is not considered
861/// allocated. A second call to `copyToTmpRegister` may return the same register.886/// allocated. A second call to `copyToTmpRegister` may return the same register.
862/// This can have a side effect of spilling instructions to the stack to free up a register.887/// This can have a side effect of spilling instructions to the stack to free up a register.
...@@ -1156,6 +1181,15 @@ fn binOpRegister(...@@ -1156,6 +1181,15 @@ fn binOpRegister(
1156 .bit_or,1181 .bit_or,
1157 .bool_or,1182 .bool_or,
1158 => .orr_shifted_register,1183 => .orr_shifted_register,
1184 .shl,
1185 .shl_exact,
1186 => .lsl_register,
1187 .shr,
1188 .shr_exact,
1189 => switch (lhs_ty.intInfo(self.target.*).signedness) {
1190 .signed => Mir.Inst.Tag.asr_register,
1191 .unsigned => Mir.Inst.Tag.lsr_register,
1192 },
1159 .xor => .eor_shifted_register,1193 .xor => .eor_shifted_register,
1160 else => unreachable,1194 else => unreachable,
1161 };1195 };
...@@ -1171,7 +1205,12 @@ fn binOpRegister(...@@ -1171,7 +1205,12 @@ fn binOpRegister(
1171 .imm6 = 0,1205 .imm6 = 0,
1172 .shift = .lsl,1206 .shift = .lsl,
1173 } },1207 } },
1174 .mul => .{ .rrr = .{1208 .mul,
1209 .shl,
1210 .shl_exact,
1211 .shr,
1212 .shr_exact,
1213 => .{ .rrr = .{
1175 .rd = dest_reg,1214 .rd = dest_reg,
1176 .rn = lhs_reg,1215 .rn = lhs_reg,
1177 .rm = rhs_reg,1216 .rm = rhs_reg,
...@@ -1263,6 +1302,15 @@ fn binOpImmediate(...@@ -1263,6 +1302,15 @@ fn binOpImmediate(
1263 const mir_tag: Mir.Inst.Tag = switch (tag) {1302 const mir_tag: Mir.Inst.Tag = switch (tag) {
1264 .add => .add_immediate,1303 .add => .add_immediate,
1265 .sub => .sub_immediate,1304 .sub => .sub_immediate,
1305 .shl,
1306 .shl_exact,
1307 => .lsl_immediate,
1308 .shr,
1309 .shr_exact,
1310 => switch (lhs_ty.intInfo(self.target.*).signedness) {
1311 .signed => Mir.Inst.Tag.asr_immediate,
1312 .unsigned => Mir.Inst.Tag.lsr_immediate,
1313 },
1266 else => unreachable,1314 else => unreachable,
1267 };1315 };
1268 const mir_data: Mir.Inst.Data = switch (tag) {1316 const mir_data: Mir.Inst.Data = switch (tag) {
...@@ -1273,6 +1321,15 @@ fn binOpImmediate(...@@ -1273,6 +1321,15 @@ fn binOpImmediate(
1273 .rn = lhs_reg,1321 .rn = lhs_reg,
1274 .imm12 = @intCast(u12, rhs.immediate),1322 .imm12 = @intCast(u12, rhs.immediate),
1275 } },1323 } },
1324 .shl,
1325 .shl_exact,
1326 .shr,
1327 .shr_exact,
1328 => .{ .rr_shift = .{
1329 .rd = dest_reg,
1330 .rn = lhs_reg,
1331 .shift = @intCast(u6, rhs.immediate),
1332 } },
1276 else => unreachable,1333 else => unreachable,
1277 };1334 };
12781335
...@@ -1304,7 +1361,7 @@ fn binOp(...@@ -1304,7 +1361,7 @@ fn binOp(
1304 rhs: MCValue,1361 rhs: MCValue,
1305 lhs_ty: Type,1362 lhs_ty: Type,
1306 rhs_ty: Type,1363 rhs_ty: Type,
1307) !MCValue {1364) InnerError!MCValue {
1308 switch (tag) {1365 switch (tag) {
1309 // Arithmetic operations on integers and floats1366 // Arithmetic operations on integers and floats
1310 .add,1367 .add,
...@@ -1385,6 +1442,28 @@ fn binOp(...@@ -1385,6 +1442,28 @@ fn binOp(
1385 else => unreachable,1442 else => unreachable,
1386 }1443 }
1387 },1444 },
1445 .shl,
1446 .shr,
1447 => {
1448 switch (lhs_ty.zigTypeTag()) {
1449 .Vector => return self.fail("TODO binary operations on vectors", .{}),
1450 .Int => {
1451 const int_info = lhs_ty.intInfo(self.target.*);
1452 if (int_info.bits <= 64) {
1453 const rhs_immediate_ok = rhs == .immediate;
1454
1455 if (rhs_immediate_ok) {
1456 return try self.binOpImmediate(tag, maybe_inst, lhs, rhs, lhs_ty, false);
1457 } else {
1458 return try self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
1459 }
1460 } else {
1461 return self.fail("TODO binary operations on int with bits > 64", .{});
1462 }
1463 },
1464 else => unreachable,
1465 }
1466 },
1388 .bool_and,1467 .bool_and,
1389 .bool_or,1468 .bool_or,
1390 => {1469 => {
...@@ -1404,16 +1483,21 @@ fn binOp(...@@ -1404,16 +1483,21 @@ fn binOp(
1404 switch (lhs_ty.zigTypeTag()) {1483 switch (lhs_ty.zigTypeTag()) {
1405 .Pointer => {1484 .Pointer => {
1406 const ptr_ty = lhs_ty;1485 const ptr_ty = lhs_ty;
1407 const pointee_ty = switch (ptr_ty.ptrSize()) {1486 const elem_ty = switch (ptr_ty.ptrSize()) {
1408 .One => ptr_ty.childType().childType(), // ptr to array, so get array element type1487 .One => ptr_ty.childType().childType(), // ptr to array, so get array element type
1409 else => ptr_ty.childType(),1488 else => ptr_ty.childType(),
1410 };1489 };
1490 const elem_size = elem_ty.abiSize(self.target.*);
14111491
1412 if (pointee_ty.abiSize(self.target.*) > 1) {1492 if (elem_size == 1) {
1413 return self.fail("TODO ptr_add, ptr_sub with more element sizes", .{});1493 return try self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
1494 } else {
1495 // convert the offset into a byte offset by
1496 // multiplying it with elem_size
1497 const offset = try self.binOp(.mul, null, rhs, .{ .immediate = elem_size }, Type.usize, Type.usize);
1498 const addr = try self.binOp(tag, null, lhs, offset, Type.initTag(.manyptr_u8), Type.usize);
1499 return addr;
1414 }1500 }
1415
1416 return try self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
1417 },1501 },
1418 else => unreachable,1502 else => unreachable,
1419 }1503 }
...@@ -1458,12 +1542,6 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void {...@@ -1458,12 +1542,6 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void {
1458 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1542 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1459}1543}
14601544
1461fn airMul(self: *Self, inst: Air.Inst.Index) !void {
1462 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1463 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement mul for {}", .{self.target.cpu.arch});
1464 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1465}
1466
1467fn airMulWrap(self: *Self, inst: Air.Inst.Index) !void {1545fn airMulWrap(self: *Self, inst: Air.Inst.Index) !void {
1468 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1546 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1469 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement mulwrap for {}", .{self.target.cpu.arch});1547 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement mulwrap for {}", .{self.target.cpu.arch});
...@@ -1514,24 +1592,12 @@ fn airMod(self: *Self, inst: Air.Inst.Index) !void {...@@ -1514,24 +1592,12 @@ fn airMod(self: *Self, inst: Air.Inst.Index) !void {
1514 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1592 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1515}1593}
15161594
1517fn airShl(self: *Self, inst: Air.Inst.Index) !void {
1518 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1519 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement shl for {}", .{self.target.cpu.arch});
1520 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1521}
1522
1523fn airShlSat(self: *Self, inst: Air.Inst.Index) !void {1595fn airShlSat(self: *Self, inst: Air.Inst.Index) !void {
1524 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1596 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1525 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement shl_sat for {}", .{self.target.cpu.arch});1597 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement shl_sat for {}", .{self.target.cpu.arch});
1526 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1598 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1527}1599}
15281600
1529fn airShr(self: *Self, inst: Air.Inst.Index) !void {
1530 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1531 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement shr for {}", .{self.target.cpu.arch});
1532 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1533}
1534
1535fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void {1601fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void {
1536 const ty_op = self.air.instructions.items(.data)[inst].ty_op;1602 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1537 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement .optional_payload for {}", .{self.target.cpu.arch});1603 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement .optional_payload for {}", .{self.target.cpu.arch});
...@@ -1735,29 +1801,11 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -1735,29 +1801,11 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
17351801
1736 switch (elem_size) {1802 switch (elem_size) {
1737 else => {1803 else => {
1738 const dst_mcv = try self.allocRegOrMem(inst, true);1804 const dest = try self.allocRegOrMem(inst, true);
17391805 const addr = try self.binOp(.ptr_add, null, base_mcv, index_mcv, slice_ty, Type.usize);
1740 const offset_mcv = try self.binOp(1806 try self.load(dest, addr, slice_ptr_field_type);
1741 .mul,
1742 null,
1743 index_mcv,
1744 .{ .immediate = elem_size },
1745 Type.usize,
1746 Type.usize,
1747 );
1748 assert(offset_mcv == .register); // result of multiplication should always be register
1749 self.register_manager.freezeRegs(&.{offset_mcv.register});
1750
1751 const addr_mcv = try self.binOp(.add, null, base_mcv, offset_mcv, Type.usize, Type.usize);
17521807
1753 // At this point in time, neither the base register1808 break :result dest;
1754 // nor the offset register contains any valuable data
1755 // anymore.
1756 self.register_manager.unfreezeRegs(&.{ base_mcv.register, offset_mcv.register });
1757
1758 try self.load(dst_mcv, addr_mcv, slice_ptr_field_type);
1759
1760 break :result dst_mcv;
1761 },1809 },
1762 }1810 }
1763 };1811 };
...@@ -2360,6 +2408,16 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions....@@ -2360,6 +2408,16 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
2360 var info = try self.resolveCallingConventionValues(fn_ty);2408 var info = try self.resolveCallingConventionValues(fn_ty);
2361 defer info.deinit(self);2409 defer info.deinit(self);
23622410
2411 // According to the Procedure Call Standard for the ARM
2412 // Architecture, compare flags are not preserved across
2413 // calls. Therefore, if some value is currently stored there, we
2414 // need to save it.
2415 //
2416 // TODO once caller-saved registers are implemented, save them
2417 // here too, but crucially *after* we save the compare flags as
2418 // saving compare flags may require a new caller-saved register
2419 try self.spillCompareFlagsIfOccupied();
2420
2363 for (info.args) |mc_arg, arg_i| {2421 for (info.args) |mc_arg, arg_i| {
2364 const arg = args[arg_i];2422 const arg = args[arg_i];
2365 const arg_ty = self.air.typeOf(arg);2423 const arg_ty = self.air.typeOf(arg);
...@@ -2551,6 +2609,9 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {...@@ -2551,6 +2609,9 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
2551 return self.fail("TODO cmp for types with size > 8", .{});2609 return self.fail("TODO cmp for types with size > 8", .{});
2552 }2610 }
25532611
2612 try self.spillCompareFlagsIfOccupied();
2613 self.compare_flags_inst = inst;
2614
2554 const signedness: std.builtin.Signedness = blk: {2615 const signedness: std.builtin.Signedness = blk: {
2555 // by default we tell the operand type is unsigned (i.e. bools and enum values)2616 // by default we tell the operand type is unsigned (i.e. bools and enum values)
2556 if (ty.zigTypeTag() != .Int) break :blk .unsigned;2617 if (ty.zigTypeTag() != .Int) break :blk .unsigned;
...@@ -2713,12 +2774,24 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {...@@ -2713,12 +2774,24 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
2713 },2774 },
2714 };2775 };
27152776
2777 // If the condition dies here in this condbr instruction, process
2778 // that death now instead of later as this has an effect on
2779 // whether it needs to be spilled in the branches
2780 if (self.liveness.operandDies(inst, 0)) {
2781 const op_int = @enumToInt(pl_op.operand);
2782 if (op_int >= Air.Inst.Ref.typed_value_map.len) {
2783 const op_index = @intCast(Air.Inst.Index, op_int - Air.Inst.Ref.typed_value_map.len);
2784 self.processDeath(op_index);
2785 }
2786 }
2787
2716 // Capture the state of register and stack allocation state so that we can revert to it.2788 // Capture the state of register and stack allocation state so that we can revert to it.
2717 const parent_next_stack_offset = self.next_stack_offset;2789 const parent_next_stack_offset = self.next_stack_offset;
2718 const parent_free_registers = self.register_manager.free_registers;2790 const parent_free_registers = self.register_manager.free_registers;
2719 var parent_stack = try self.stack.clone(self.gpa);2791 var parent_stack = try self.stack.clone(self.gpa);
2720 defer parent_stack.deinit(self.gpa);2792 defer parent_stack.deinit(self.gpa);
2721 const parent_registers = self.register_manager.registers;2793 const parent_registers = self.register_manager.registers;
2794 const parent_compare_flags_inst = self.compare_flags_inst;
27222795
2723 try self.branch_stack.append(.{});2796 try self.branch_stack.append(.{});
27242797
...@@ -2734,6 +2807,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {...@@ -2734,6 +2807,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
2734 defer saved_then_branch.deinit(self.gpa);2807 defer saved_then_branch.deinit(self.gpa);
27352808
2736 self.register_manager.registers = parent_registers;2809 self.register_manager.registers = parent_registers;
2810 self.compare_flags_inst = parent_compare_flags_inst;
27372811
2738 self.stack.deinit(self.gpa);2812 self.stack.deinit(self.gpa);
2739 self.stack = parent_stack;2813 self.stack = parent_stack;
...@@ -2825,7 +2899,9 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {...@@ -2825,7 +2899,9 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
28252899
2826 self.branch_stack.pop().deinit(self.gpa);2900 self.branch_stack.pop().deinit(self.gpa);
28272901
2828 return self.finishAir(inst, .unreach, .{ pl_op.operand, .none, .none });2902 // We already took care of pl_op.operand earlier, so we're going
2903 // to pass .none here
2904 return self.finishAir(inst, .unreach, .{ .none, .none, .none });
2829}2905}
28302906
2831fn isNull(self: *Self, operand: MCValue) !MCValue {2907fn isNull(self: *Self, operand: MCValue) !MCValue {
...@@ -2843,8 +2919,6 @@ fn isNonNull(self: *Self, operand: MCValue) !MCValue {...@@ -2843,8 +2919,6 @@ fn isNonNull(self: *Self, operand: MCValue) !MCValue {
2843}2919}
28442920
2845fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {2921fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
2846 _ = operand;
2847
2848 const error_type = ty.errorUnionSet();2922 const error_type = ty.errorUnionSet();
2849 const payload_type = ty.errorUnionPayload();2923 const payload_type = ty.errorUnionPayload();
28502924
...@@ -3323,7 +3397,13 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro...@@ -3323,7 +3397,13 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
3323 const reg = try self.copyToTmpRegister(ty, mcv);3397 const reg = try self.copyToTmpRegister(ty, mcv);
3324 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });3398 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });
3325 } else {3399 } else {
3326 // TODO optimize the register allocation3400 var ptr_ty_payload: Type.Payload.ElemType = .{
3401 .base = .{ .tag = .single_mut_pointer },
3402 .data = ty,
3403 };
3404 const ptr_ty = Type.initPayload(&ptr_ty_payload.base);
3405
3406 // TODO call extern memcpy
3327 const regs = try self.register_manager.allocRegs(5, .{ null, null, null, null, null });3407 const regs = try self.register_manager.allocRegs(5, .{ null, null, null, null, null });
3328 self.register_manager.freezeRegs(&regs);3408 self.register_manager.freezeRegs(&regs);
3329 defer self.register_manager.unfreezeRegs(&regs);3409 defer self.register_manager.unfreezeRegs(&regs);
...@@ -3337,16 +3417,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro...@@ -3337,16 +3417,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
3337 switch (mcv) {3417 switch (mcv) {
3338 .stack_offset => |off| {3418 .stack_offset => |off| {
3339 // sub src_reg, fp, #off3419 // sub src_reg, fp, #off
3340 const adj_src_offset = off + abi_size;3420 try self.genSetReg(ptr_ty, src_reg, .{ .ptr_stack_offset = off });
3341 const src_offset = math.cast(u12, adj_src_offset) catch return self.fail("TODO load: larger stack offsets", .{});
3342 _ = try self.addInst(.{
3343 .tag = .sub_immediate,
3344 .data = .{ .rr_imm12_sh = .{
3345 .rd = src_reg,
3346 .rn = .x29,
3347 .imm12 = src_offset,
3348 } },
3349 });
3350 },3421 },
3351 .memory => |addr| try self.genSetReg(Type.usize, src_reg, .{ .immediate = addr }),3422 .memory => |addr| try self.genSetReg(Type.usize, src_reg, .{ .immediate = addr }),
3352 .got_load,3423 .got_load,
...@@ -3372,16 +3443,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro...@@ -3372,16 +3443,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
3372 }3443 }
33733444
3374 // sub dst_reg, fp, #stack_offset3445 // sub dst_reg, fp, #stack_offset
3375 const adj_dst_off = stack_offset + abi_size;3446 try self.genSetReg(ptr_ty, dst_reg, .{ .ptr_stack_offset = stack_offset });
3376 const dst_offset = math.cast(u12, adj_dst_off) catch return self.fail("TODO load: larger stack offsets", .{});
3377 _ = try self.addInst(.{
3378 .tag = .sub_immediate,
3379 .data = .{ .rr_imm12_sh = .{
3380 .rd = dst_reg,
3381 .rn = .x29,
3382 .imm12 = dst_offset,
3383 } },
3384 });
33853447
3386 // mov len, #abi_size3448 // mov len, #abi_size
3387 try self.genSetReg(Type.usize, len_reg, .{ .immediate = abi_size });3449 try self.genSetReg(Type.usize, len_reg, .{ .immediate = abi_size });
src/arch/aarch64/Emit.zig+38-14
...@@ -80,6 +80,14 @@ pub fn emitMir(...@@ -80,6 +80,14 @@ pub fn emitMir(
80 .cmp_immediate => try emit.mirAddSubtractImmediate(inst),80 .cmp_immediate => try emit.mirAddSubtractImmediate(inst),
81 .sub_immediate => try emit.mirAddSubtractImmediate(inst),81 .sub_immediate => try emit.mirAddSubtractImmediate(inst),
8282
83 .asr_register => try emit.mirShiftRegister(inst),
84 .lsl_register => try emit.mirShiftRegister(inst),
85 .lsr_register => try emit.mirShiftRegister(inst),
86
87 .asr_immediate => try emit.mirShiftImmediate(inst),
88 .lsl_immediate => try emit.mirShiftImmediate(inst),
89 .lsr_immediate => try emit.mirShiftImmediate(inst),
90
83 .b_cond => try emit.mirConditionalBranchImmediate(inst),91 .b_cond => try emit.mirConditionalBranchImmediate(inst),
8492
85 .b => try emit.mirBranch(inst),93 .b => try emit.mirBranch(inst),
...@@ -374,20 +382,6 @@ fn fail(emit: *Emit, comptime format: []const u8, args: anytype) InnerError {...@@ -374,20 +382,6 @@ fn fail(emit: *Emit, comptime format: []const u8, args: anytype) InnerError {
374 return error.EmitFail;382 return error.EmitFail;
375}383}
376384
377fn moveImmediate(emit: *Emit, reg: Register, imm64: u64) !void {
378 try emit.writeInstruction(Instruction.movz(reg, @truncate(u16, imm64), 0));
379
380 if (imm64 > math.maxInt(u16)) {
381 try emit.writeInstruction(Instruction.movk(reg, @truncate(u16, imm64 >> 16), 16));
382 }
383 if (imm64 > math.maxInt(u32)) {
384 try emit.writeInstruction(Instruction.movk(reg, @truncate(u16, imm64 >> 32), 32));
385 }
386 if (imm64 > math.maxInt(u48)) {
387 try emit.writeInstruction(Instruction.movk(reg, @truncate(u16, imm64 >> 48), 48));
388 }
389}
390
391fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void {385fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void {
392 const delta_line = @intCast(i32, line) - @intCast(i32, self.prev_di_line);386 const delta_line = @intCast(i32, line) - @intCast(i32, self.prev_di_line);
393 const delta_pc: usize = self.code.items.len - self.prev_di_pc;387 const delta_pc: usize = self.code.items.len - self.prev_di_pc;
...@@ -469,6 +463,36 @@ fn mirAddSubtractImmediate(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -469,6 +463,36 @@ fn mirAddSubtractImmediate(emit: *Emit, inst: Mir.Inst.Index) !void {
469 }463 }
470}464}
471465
466fn mirShiftRegister(emit: *Emit, inst: Mir.Inst.Index) !void {
467 const tag = emit.mir.instructions.items(.tag)[inst];
468 const rrr = emit.mir.instructions.items(.data)[inst].rrr;
469 const rd = rrr.rd;
470 const rn = rrr.rn;
471 const rm = rrr.rm;
472
473 switch (tag) {
474 .asr_register => try emit.writeInstruction(Instruction.asrRegister(rd, rn, rm)),
475 .lsl_register => try emit.writeInstruction(Instruction.lslRegister(rd, rn, rm)),
476 .lsr_register => try emit.writeInstruction(Instruction.lsrRegister(rd, rn, rm)),
477 else => unreachable,
478 }
479}
480
481fn mirShiftImmediate(emit: *Emit, inst: Mir.Inst.Index) !void {
482 const tag = emit.mir.instructions.items(.tag)[inst];
483 const rr_shift = emit.mir.instructions.items(.data)[inst].rr_shift;
484 const rd = rr_shift.rd;
485 const rn = rr_shift.rn;
486 const shift = rr_shift.shift;
487
488 switch (tag) {
489 .asr_immediate => try emit.writeInstruction(Instruction.asrImmediate(rd, rn, shift)),
490 .lsl_immediate => try emit.writeInstruction(Instruction.lslImmediate(rd, rn, shift)),
491 .lsr_immediate => try emit.writeInstruction(Instruction.lsrImmediate(rd, rn, shift)),
492 else => unreachable,
493 }
494}
495
472fn mirConditionalBranchImmediate(emit: *Emit, inst: Mir.Inst.Index) !void {496fn mirConditionalBranchImmediate(emit: *Emit, inst: Mir.Inst.Index) !void {
473 const tag = emit.mir.instructions.items(.tag)[inst];497 const tag = emit.mir.instructions.items(.tag)[inst];
474 const inst_cond = emit.mir.instructions.items(.data)[inst].inst_cond;498 const inst_cond = emit.mir.instructions.items(.data)[inst].inst_cond;
src/arch/aarch64/Mir.zig+21-1
...@@ -30,6 +30,10 @@ pub const Inst = struct {...@@ -30,6 +30,10 @@ pub const Inst = struct {
30 add_shifted_register,30 add_shifted_register,
31 /// Bitwise AND (shifted register)31 /// Bitwise AND (shifted register)
32 and_shifted_register,32 and_shifted_register,
33 /// Arithmetic Shift Right (immediate)
34 asr_immediate,
35 /// Arithmetic Shift Right (register)
36 asr_register,
33 /// Branch conditionally37 /// Branch conditionally
34 b_cond,38 b_cond,
35 /// Branch39 /// Branch
...@@ -96,6 +100,14 @@ pub const Inst = struct {...@@ -96,6 +100,14 @@ pub const Inst = struct {
96 ldrh_immediate,100 ldrh_immediate,
97 /// Load Register Halfword (register)101 /// Load Register Halfword (register)
98 ldrh_register,102 ldrh_register,
103 /// Logical Shift Left (immediate)
104 lsl_immediate,
105 /// Logical Shift Left (register)
106 lsl_register,
107 /// Logical Shift Right (immediate)
108 lsr_immediate,
109 /// Logical Shift Right (register)
110 lsr_register,
99 /// Move (to/from SP)111 /// Move (to/from SP)
100 mov_to_from_sp,112 mov_to_from_sp,
101 /// Move (register)113 /// Move (register)
...@@ -257,7 +269,15 @@ pub const Inst = struct {...@@ -257,7 +269,15 @@ pub const Inst = struct {
257 immr: u6,269 immr: u6,
258 n: u1,270 n: u1,
259 },271 },
260 /// Two registers272 /// Two registers and a 6-bit unsigned shift
273 ///
274 /// Used by e.g. lsl_immediate
275 rr_shift: struct {
276 rd: Register,
277 rn: Register,
278 shift: u6,
279 },
280 /// Three registers
261 ///281 ///
262 /// Used by e.g. mul282 /// Used by e.g. mul
263 rrr: struct {283 rrr: struct {
src/arch/aarch64/bits.zig+152
...@@ -308,6 +308,16 @@ pub const Instruction = union(enum) {...@@ -308,6 +308,16 @@ pub const Instruction = union(enum) {
308 opc: u2,308 opc: u2,
309 sf: u1,309 sf: u1,
310 },310 },
311 bitfield: packed struct {
312 rd: u5,
313 rn: u5,
314 imms: u6,
315 immr: u6,
316 n: u1,
317 fixed: u6 = 0b100110,
318 opc: u2,
319 sf: u1,
320 },
311 add_subtract_shifted_register: packed struct {321 add_subtract_shifted_register: packed struct {
312 rd: u5,322 rd: u5,
313 rn: u5,323 rn: u5,
...@@ -356,6 +366,16 @@ pub const Instruction = union(enum) {...@@ -356,6 +366,16 @@ pub const Instruction = union(enum) {
356 op54: u2,366 op54: u2,
357 sf: u1,367 sf: u1,
358 },368 },
369 data_processing_2_source: packed struct {
370 rd: u5,
371 rn: u5,
372 opcode: u6,
373 rm: u5,
374 fixed_1: u8 = 0b11010110,
375 s: u1,
376 fixed_2: u1 = 0b0,
377 sf: u1,
378 },
359379
360 pub const Condition = enum(u4) {380 pub const Condition = enum(u4) {
361 /// Integer: Equal381 /// Integer: Equal
...@@ -473,12 +493,14 @@ pub const Instruction = union(enum) {...@@ -473,12 +493,14 @@ pub const Instruction = union(enum) {
473 .logical_shifted_register => |v| @bitCast(u32, v),493 .logical_shifted_register => |v| @bitCast(u32, v),
474 .add_subtract_immediate => |v| @bitCast(u32, v),494 .add_subtract_immediate => |v| @bitCast(u32, v),
475 .logical_immediate => |v| @bitCast(u32, v),495 .logical_immediate => |v| @bitCast(u32, v),
496 .bitfield => |v| @bitCast(u32, v),
476 .add_subtract_shifted_register => |v| @bitCast(u32, v),497 .add_subtract_shifted_register => |v| @bitCast(u32, v),
477 // TODO once packed structs work, this can be refactored498 // TODO once packed structs work, this can be refactored
478 .conditional_branch => |v| @as(u32, v.cond) | (@as(u32, v.o0) << 4) | (@as(u32, v.imm19) << 5) | (@as(u32, v.o1) << 24) | (@as(u32, v.fixed) << 25),499 .conditional_branch => |v| @as(u32, v.cond) | (@as(u32, v.o0) << 4) | (@as(u32, v.imm19) << 5) | (@as(u32, v.o1) << 24) | (@as(u32, v.fixed) << 25),
479 .compare_and_branch => |v| @as(u32, v.rt) | (@as(u32, v.imm19) << 5) | (@as(u32, v.op) << 24) | (@as(u32, v.fixed) << 25) | (@as(u32, v.sf) << 31),500 .compare_and_branch => |v| @as(u32, v.rt) | (@as(u32, v.imm19) << 5) | (@as(u32, v.op) << 24) | (@as(u32, v.fixed) << 25) | (@as(u32, v.sf) << 31),
480 .conditional_select => |v| @as(u32, v.rd) | @as(u32, v.rn) << 5 | @as(u32, v.op2) << 10 | @as(u32, v.cond) << 12 | @as(u32, v.rm) << 16 | @as(u32, v.fixed) << 21 | @as(u32, v.s) << 29 | @as(u32, v.op) << 30 | @as(u32, v.sf) << 31,501 .conditional_select => |v| @as(u32, v.rd) | @as(u32, v.rn) << 5 | @as(u32, v.op2) << 10 | @as(u32, v.cond) << 12 | @as(u32, v.rm) << 16 | @as(u32, v.fixed) << 21 | @as(u32, v.s) << 29 | @as(u32, v.op) << 30 | @as(u32, v.sf) << 31,
481 .data_processing_3_source => |v| @bitCast(u32, v),502 .data_processing_3_source => |v| @bitCast(u32, v),
503 .data_processing_2_source => |v| @bitCast(u32, v),
482 };504 };
483 }505 }
484506
...@@ -911,6 +933,31 @@ pub const Instruction = union(enum) {...@@ -911,6 +933,31 @@ pub const Instruction = union(enum) {
911 };933 };
912 }934 }
913935
936 fn bitfield(
937 opc: u2,
938 n: u1,
939 rd: Register,
940 rn: Register,
941 immr: u6,
942 imms: u6,
943 ) Instruction {
944 return Instruction{
945 .bitfield = .{
946 .rd = rd.enc(),
947 .rn = rn.enc(),
948 .imms = imms,
949 .immr = immr,
950 .n = n,
951 .opc = opc,
952 .sf = switch (rd.size()) {
953 32 => 0b0,
954 64 => 0b1,
955 else => unreachable, // unexpected register size
956 },
957 },
958 };
959 }
960
914 pub const AddSubtractShiftedRegisterShift = enum(u2) { lsl, lsr, asr, _ };961 pub const AddSubtractShiftedRegisterShift = enum(u2) { lsl, lsr, asr, _ };
915962
916 fn addSubtractShiftedRegister(963 fn addSubtractShiftedRegister(
...@@ -1031,6 +1078,29 @@ pub const Instruction = union(enum) {...@@ -1031,6 +1078,29 @@ pub const Instruction = union(enum) {
1031 };1078 };
1032 }1079 }
10331080
1081 fn dataProcessing2Source(
1082 s: u1,
1083 opcode: u6,
1084 rd: Register,
1085 rn: Register,
1086 rm: Register,
1087 ) Instruction {
1088 return Instruction{
1089 .data_processing_2_source = .{
1090 .rd = rd.enc(),
1091 .rn = rn.enc(),
1092 .opcode = opcode,
1093 .rm = rm.enc(),
1094 .s = s,
1095 .sf = switch (rd.size()) {
1096 32 => 0b0,
1097 64 => 0b1,
1098 else => unreachable, // unexpected register size
1099 },
1100 },
1101 };
1102 }
1103
1034 // Helper functions for assembly syntax functions1104 // Helper functions for assembly syntax functions
10351105
1036 // Move wide (immediate)1106 // Move wide (immediate)
...@@ -1300,6 +1370,50 @@ pub const Instruction = union(enum) {...@@ -1300,6 +1370,50 @@ pub const Instruction = union(enum) {
1300 return logicalImmediate(0b11, rd, rn, imms, immr, n);1370 return logicalImmediate(0b11, rd, rn, imms, immr, n);
1301 }1371 }
13021372
1373 // Bitfield
1374
1375 pub fn sbfm(rd: Register, rn: Register, immr: u6, imms: u6) Instruction {
1376 const n: u1 = switch (rd.size()) {
1377 32 => 0b0,
1378 64 => 0b1,
1379 else => unreachable, // unexpected register size
1380 };
1381 return bitfield(0b00, n, rd, rn, immr, imms);
1382 }
1383
1384 pub fn bfm(rd: Register, rn: Register, immr: u6, imms: u6) Instruction {
1385 const n: u1 = switch (rd.size()) {
1386 32 => 0b0,
1387 64 => 0b1,
1388 else => unreachable, // unexpected register size
1389 };
1390 return bitfield(0b01, n, rd, rn, immr, imms);
1391 }
1392
1393 pub fn ubfm(rd: Register, rn: Register, immr: u6, imms: u6) Instruction {
1394 const n: u1 = switch (rd.size()) {
1395 32 => 0b0,
1396 64 => 0b1,
1397 else => unreachable, // unexpected register size
1398 };
1399 return bitfield(0b10, n, rd, rn, immr, imms);
1400 }
1401
1402 pub fn asrImmediate(rd: Register, rn: Register, shift: u6) Instruction {
1403 const imms = @intCast(u6, rd.size() - 1);
1404 return sbfm(rd, rn, shift, imms);
1405 }
1406
1407 pub fn lslImmediate(rd: Register, rn: Register, shift: u6) Instruction {
1408 const size = @intCast(u6, rd.size() - 1);
1409 return ubfm(rd, rn, size - shift + 1, size - shift);
1410 }
1411
1412 pub fn lsrImmediate(rd: Register, rn: Register, shift: u6) Instruction {
1413 const imms = @intCast(u6, rd.size() - 1);
1414 return ubfm(rd, rn, shift, imms);
1415 }
1416
1303 // Add/subtract (shifted register)1417 // Add/subtract (shifted register)
13041418
1305 pub fn addShiftedRegister(1419 pub fn addShiftedRegister(
...@@ -1393,6 +1507,24 @@ pub const Instruction = union(enum) {...@@ -1393,6 +1507,24 @@ pub const Instruction = union(enum) {
1393 pub fn mneg(rd: Register, rn: Register, rm: Register) Instruction {1507 pub fn mneg(rd: Register, rn: Register, rm: Register) Instruction {
1394 return msub(rd, rn, rm, .xzr);1508 return msub(rd, rn, rm, .xzr);
1395 }1509 }
1510
1511 // Data processing (2 source)
1512
1513 pub fn lslv(rd: Register, rn: Register, rm: Register) Instruction {
1514 return dataProcessing2Source(0b0, 0b001000, rd, rn, rm);
1515 }
1516
1517 pub fn lsrv(rd: Register, rn: Register, rm: Register) Instruction {
1518 return dataProcessing2Source(0b0, 0b001001, rd, rn, rm);
1519 }
1520
1521 pub fn asrv(rd: Register, rn: Register, rm: Register) Instruction {
1522 return dataProcessing2Source(0b0, 0b001010, rd, rn, rm);
1523 }
1524
1525 pub const asrRegister = asrv;
1526 pub const lslRegister = lslv;
1527 pub const lsrRegister = lsrv;
1396};1528};
13971529
1398test {1530test {
...@@ -1570,6 +1702,26 @@ test "serialize instructions" {...@@ -1570,6 +1702,26 @@ test "serialize instructions" {
1570 .inst = Instruction.eorImmediate(.x3, .x5, 0b000000, 0b000000, 0b1),1702 .inst = Instruction.eorImmediate(.x3, .x5, 0b000000, 0b000000, 0b1),
1571 .expected = 0b1_10_100100_1_000000_000000_00101_00011,1703 .expected = 0b1_10_100100_1_000000_000000_00101_00011,
1572 },1704 },
1705 .{ // lslv x6, x9, x10
1706 .inst = Instruction.lslv(.x6, .x9, .x10),
1707 .expected = 0b1_0_0_11010110_01010_0010_00_01001_00110,
1708 },
1709 .{ // lsl x4, x2, #42
1710 .inst = Instruction.lslImmediate(.x4, .x2, 42),
1711 .expected = 0b1_10_100110_1_010110_010101_00010_00100,
1712 },
1713 .{ // lsl x4, x2, #63
1714 .inst = Instruction.lslImmediate(.x4, .x2, 63),
1715 .expected = 0b1_10_100110_1_000001_000000_00010_00100,
1716 },
1717 .{ // lsr x4, x2, #42
1718 .inst = Instruction.lsrImmediate(.x4, .x2, 42),
1719 .expected = 0b1_10_100110_1_101010_111111_00010_00100,
1720 },
1721 .{ // lsr x4, x2, #63
1722 .inst = Instruction.lsrImmediate(.x4, .x2, 63),
1723 .expected = 0b1_10_100110_1_111111_111111_00010_00100,
1724 },
1573 };1725 };
15741726
1575 for (testcases) |case| {1727 for (testcases) |case| {
test/behavior/align.zig-1
...@@ -351,7 +351,6 @@ test "read 128-bit field from default aligned struct in global memory" {...@@ -351,7 +351,6 @@ test "read 128-bit field from default aligned struct in global memory" {
351}351}
352352
353test "struct field explicit alignment" {353test "struct field explicit alignment" {
354 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
355 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;354 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
356 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;355 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
357 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;356 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
test/behavior/array.zig-1
...@@ -7,7 +7,6 @@ const expectEqual = testing.expectEqual;...@@ -7,7 +7,6 @@ const expectEqual = testing.expectEqual;
77
8test "array to slice" {8test "array to slice" {
9 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;9 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
10 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1110
12 const a: u32 align(4) = 3;11 const a: u32 align(4) = 3;
13 const b: u32 align(8) = 4;12 const b: u32 align(8) = 4;
test/behavior/bitcast.zig-1
...@@ -269,7 +269,6 @@ test "bitcast passed as tuple element" {...@@ -269,7 +269,6 @@ test "bitcast passed as tuple element" {
269269
270test "triple level result location with bitcast sandwich passed as tuple element" {270test "triple level result location with bitcast sandwich passed as tuple element" {
271 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;271 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
272 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
273 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;272 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
274273
275 const S = struct {274 const S = struct {
test/behavior/bugs/5474.zig-2
...@@ -50,7 +50,6 @@ fn constant() !void {...@@ -50,7 +50,6 @@ fn constant() !void {
5050
51test "pointer-to-array constness for zero-size elements, var" {51test "pointer-to-array constness for zero-size elements, var" {
52 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO52 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
53 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
5453
55 try mutable();54 try mutable();
56 comptime try mutable();55 comptime try mutable();
...@@ -58,7 +57,6 @@ test "pointer-to-array constness for zero-size elements, var" {...@@ -58,7 +57,6 @@ test "pointer-to-array constness for zero-size elements, var" {
5857
59test "pointer-to-array constness for zero-size elements, const" {58test "pointer-to-array constness for zero-size elements, const" {
60 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO59 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
61 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
6260
63 try constant();61 try constant();
64 comptime try constant();62 comptime try constant();
test/behavior/math.zig-1
...@@ -573,7 +573,6 @@ test "bit shift a u1" {...@@ -573,7 +573,6 @@ test "bit shift a u1" {
573573
574test "truncating shift right" {574test "truncating shift right" {
575 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO575 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
576 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
577576
578 try testShrTrunc(maxInt(u16));577 try testShrTrunc(maxInt(u16));
579 comptime try testShrTrunc(maxInt(u16));578 comptime try testShrTrunc(maxInt(u16));
test/behavior/sizeof_and_typeof.zig-2
...@@ -187,7 +187,6 @@ test "@sizeOf(T) == 0 doesn't force resolving struct size" {...@@ -187,7 +187,6 @@ test "@sizeOf(T) == 0 doesn't force resolving struct size" {
187187
188test "@TypeOf() has no runtime side effects" {188test "@TypeOf() has no runtime side effects" {
189 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;189 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
190 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
191 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;190 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
192 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;191 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
193 const S = struct {192 const S = struct {
...@@ -204,7 +203,6 @@ test "@TypeOf() has no runtime side effects" {...@@ -204,7 +203,6 @@ test "@TypeOf() has no runtime side effects" {
204203
205test "branching logic inside @TypeOf" {204test "branching logic inside @TypeOf" {
206 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;205 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
207 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
208 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;206 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
209 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;207 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
210 const S = struct {208 const S = struct {
test/behavior/slice.zig-1
...@@ -204,7 +204,6 @@ test "slicing zero length array" {...@@ -204,7 +204,6 @@ test "slicing zero length array" {
204const x = @intToPtr([*]i32, 0x1000)[0..0x500];204const x = @intToPtr([*]i32, 0x1000)[0..0x500];
205const y = x[0x100..];205const y = x[0x100..];
206test "compile time slice of pointer to hard coded address" {206test "compile time slice of pointer to hard coded address" {
207 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
208 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO207 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
209 if (builtin.zig_backend == .stage1) return error.SkipZigTest;208 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
210 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;209 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
test/behavior/struct.zig-3
...@@ -927,7 +927,6 @@ test "anonymous struct literal syntax" {...@@ -927,7 +927,6 @@ test "anonymous struct literal syntax" {
927test "fully anonymous struct" {927test "fully anonymous struct" {
928 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO928 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
929 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO929 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
930 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
931930
932 const S = struct {931 const S = struct {
933 fn doTheTest() !void {932 fn doTheTest() !void {
...@@ -953,7 +952,6 @@ test "fully anonymous struct" {...@@ -953,7 +952,6 @@ test "fully anonymous struct" {
953test "fully anonymous list literal" {952test "fully anonymous list literal" {
954 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO953 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
955 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO954 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
956 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
957955
958 const S = struct {956 const S = struct {
959 fn doTheTest() !void {957 fn doTheTest() !void {
...@@ -983,7 +981,6 @@ test "tuple assigned to variable" {...@@ -983,7 +981,6 @@ test "tuple assigned to variable" {
983981
984test "comptime struct field" {982test "comptime struct field" {
985 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO983 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
986 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
987984
988 const T = struct {985 const T = struct {
989 a: i32,986 a: i32,
test/behavior/var_args.zig-4
...@@ -15,7 +15,6 @@ fn add(args: anytype) i32 {...@@ -15,7 +15,6 @@ fn add(args: anytype) i32 {
15test "add arbitrary args" {15test "add arbitrary args" {
16 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO16 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
17 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO17 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
18 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1918
20 try expect(add(.{ @as(i32, 1), @as(i32, 2), @as(i32, 3), @as(i32, 4) }) == 10);19 try expect(add(.{ @as(i32, 1), @as(i32, 2), @as(i32, 3), @as(i32, 4) }) == 10);
21 try expect(add(.{@as(i32, 1234)}) == 1234);20 try expect(add(.{@as(i32, 1234)}) == 1234);
...@@ -27,7 +26,6 @@ fn readFirstVarArg(args: anytype) void {...@@ -27,7 +26,6 @@ fn readFirstVarArg(args: anytype) void {
27}26}
2827
29test "send void arg to var args" {28test "send void arg to var args" {
30 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
31 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO29 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
32 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO30 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
3331
...@@ -90,7 +88,6 @@ fn foo2(args: anytype) bool {...@@ -90,7 +88,6 @@ fn foo2(args: anytype) bool {
90}88}
9189
92test "array of var args functions" {90test "array of var args functions" {
93 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
94 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO91 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
95 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO92 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
9693
...@@ -99,7 +96,6 @@ test "array of var args functions" {...@@ -99,7 +96,6 @@ test "array of var args functions" {
99}96}
10097
101test "pass zero length array to var args param" {98test "pass zero length array to var args param" {
102 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
103 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO99 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
104 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO100 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
105101