authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-06-07 11:08:45+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-06-07 23:34:42-04:00
log61844b6bd405b4cca3ab673284609aa6a651d506
treef596f02022a846d6d0a689b076b7bb6895e3c89d
parent70dc910086582b028d404d5de5049ceae0a95161

stage2 AArch64: introduce MCValue.condition_flags

Follows 9747303d16dfca61316a292d1e05ac901191e3a3 for AArch64

1 files changed, 41 insertions(+), 100 deletions(-)

src/arch/aarch64/CodeGen.zig+41-100
......@@ -35,6 +35,7 @@ const RegisterManager = abi.RegisterManager;
3535const RegisterLock = RegisterManager.RegisterLock;
3636const Register = bits.Register;
3737const Instruction = bits.Instruction;
38const Condition = bits.Instruction.Condition;
3839const callee_preserved_regs = abi.callee_preserved_regs;
3940const c_abi_int_param_regs = abi.c_abi_int_param_regs;
4041const c_abi_int_return_regs = abi.c_abi_int_return_regs;
......@@ -90,7 +91,7 @@ register_manager: RegisterManager = .{},
9091/// Maps offset to what is stored there.
9192stack: std.AutoHashMapUnmanaged(u32, StackAllocation) = .{},
9293/// Tracks the current instruction allocated to the compare flags
93compare_flags_inst: ?Air.Inst.Index = null,
94condition_flags_inst: ?Air.Inst.Index = null,
9495
9596/// Offset from the stack base, representing the end of the stack frame.
9697max_end_stack: u32 = 0,
......@@ -161,12 +162,10 @@ const MCValue = union(enum) {
161162 /// The value is a pointer to one of the stack variables (payload
162163 /// is stack offset).
163164 ptr_stack_offset: u32,
164 /// The value is in the compare flags assuming an unsigned
165 /// operation, with this operator applied on top of it.
166 compare_flags_unsigned: math.CompareOperator,
167 /// The value is in the compare flags assuming a signed operation,
168 /// with this operator applied on top of it.
169 compare_flags_signed: math.CompareOperator,
165 /// The value resides in the N, Z, C, V flags. The value is 1 (if
166 /// the type is u1) or true (if the type in bool) iff the
167 /// specified condition is true.
168 condition_flags: Condition,
170169
171170 fn isMemory(mcv: MCValue) bool {
172171 return switch (mcv) {
......@@ -190,8 +189,7 @@ const MCValue = union(enum) {
190189
191190 .immediate,
192191 .memory,
193 .compare_flags_unsigned,
194 .compare_flags_signed,
192 .condition_flags,
195193 .ptr_stack_offset,
196194 .undef,
197195 => false,
......@@ -758,10 +756,10 @@ fn processDeath(self: *Self, inst: Air.Inst.Index) void {
758756 },
759757 .register_with_overflow => |rwo| {
760758 self.register_manager.freeReg(rwo.reg);
761 self.compare_flags_inst = null;
759 self.condition_flags_inst = null;
762760 },
763 .compare_flags_signed, .compare_flags_unsigned => {
764 self.compare_flags_inst = null;
761 .condition_flags => {
762 self.condition_flags_inst = null;
765763 },
766764 else => {}, // TODO process stack allocation death
767765 }
......@@ -911,12 +909,10 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void
911909/// Save the current instruction stored in the compare flags if
912910/// occupied
913911fn spillCompareFlagsIfOccupied(self: *Self) !void {
914 if (self.compare_flags_inst) |inst_to_save| {
912 if (self.condition_flags_inst) |inst_to_save| {
915913 const mcv = self.getResolvedInstValue(inst_to_save);
916914 const new_mcv = switch (mcv) {
917 .compare_flags_signed,
918 .compare_flags_unsigned,
919 => try self.allocRegOrMem(inst_to_save, true),
915 .condition_flags => try self.allocRegOrMem(inst_to_save, true),
920916 .register_with_overflow => try self.allocRegOrMem(inst_to_save, false),
921917 else => unreachable, // mcv doesn't occupy the compare flags
922918 };
......@@ -927,7 +923,7 @@ fn spillCompareFlagsIfOccupied(self: *Self) !void {
927923 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
928924 try branch.inst_table.put(self.gpa, inst_to_save, new_mcv);
929925
930 self.compare_flags_inst = null;
926 self.condition_flags_inst = null;
931927
932928 // TODO consolidate with register manager and spillInstruction
933929 // this call should really belong in the register manager!
......@@ -1109,32 +1105,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {
11091105 switch (operand) {
11101106 .dead => unreachable,
11111107 .unreach => unreachable,
1112 .compare_flags_unsigned => |op| {
1113 const r = MCValue{
1114 .compare_flags_unsigned = switch (op) {
1115 .gte => .lt,
1116 .gt => .lte,
1117 .neq => .eq,
1118 .lt => .gte,
1119 .lte => .gt,
1120 .eq => .neq,
1121 },
1122 };
1123 break :result r;
1124 },
1125 .compare_flags_signed => |op| {
1126 const r = MCValue{
1127 .compare_flags_signed = switch (op) {
1128 .gte => .lt,
1129 .gt => .lte,
1130 .neq => .eq,
1131 .lt => .gte,
1132 .lte => .gt,
1133 .eq => .neq,
1134 },
1135 };
1136 break :result r;
1137 },
1108 .condition_flags => |cond| break :result MCValue{ .condition_flags = cond.negate() },
11381109 else => {
11391110 switch (operand_ty.zigTypeTag()) {
11401111 .Bool => {
......@@ -1851,7 +1822,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {
18511822 const stack_offset = try self.allocMem(inst, tuple_size, tuple_align);
18521823
18531824 try self.spillCompareFlagsIfOccupied();
1854 self.compare_flags_inst = null;
1825 self.condition_flags_inst = null;
18551826
18561827 const base_tag: Air.Inst.Tag = switch (tag) {
18571828 .add_with_overflow => .add,
......@@ -1875,7 +1846,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {
18751846 _ = try self.binOp(.cmp_eq, dest, .{ .register = truncated_reg }, Type.usize, Type.usize, null);
18761847
18771848 try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg });
1878 try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .compare_flags_unsigned = .neq });
1849 try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .condition_flags = .ne });
18791850
18801851 break :result MCValue{ .stack_offset = stack_offset };
18811852 },
......@@ -1907,7 +1878,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {
19071878 };
19081879
19091880 try self.spillCompareFlagsIfOccupied();
1910 self.compare_flags_inst = inst;
1881 self.condition_flags_inst = inst;
19111882
19121883 const dest = blk: {
19131884 if (rhs_immediate_ok) {
......@@ -1966,7 +1937,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
19661937 const stack_offset = try self.allocMem(inst, tuple_size, tuple_align);
19671938
19681939 try self.spillCompareFlagsIfOccupied();
1969 self.compare_flags_inst = null;
1940 self.condition_flags_inst = null;
19701941
19711942 const base_tag: Mir.Inst.Tag = switch (int_info.signedness) {
19721943 .signed => .smull,
......@@ -2015,16 +1986,14 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
20151986 }
20161987
20171988 try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg });
2018 try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{
2019 .compare_flags_unsigned = .neq,
2020 });
1989 try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .condition_flags = .ne });
20211990
20221991 break :result MCValue{ .stack_offset = stack_offset };
20231992 } else if (int_info.bits <= 64) {
20241993 const stack_offset = try self.allocMem(inst, tuple_size, tuple_align);
20251994
20261995 try self.spillCompareFlagsIfOccupied();
2027 self.compare_flags_inst = null;
1996 self.condition_flags_inst = null;
20281997
20291998 // TODO this should really be put in a helper similar to `binOpRegister`
20301999 const lhs_is_register = lhs == .register;
......@@ -2194,9 +2163,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
21942163 try self.truncRegister(dest_reg, truncated_reg, int_info.signedness, int_info.bits);
21952164
21962165 try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg });
2197 try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{
2198 .compare_flags_unsigned = .neq,
2199 });
2166 try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .condition_flags = .ne });
22002167
22012168 break :result MCValue{ .stack_offset = stack_offset };
22022169 } else return self.fail("TODO implement mul_with_overflow for integers > u64/i64", .{});
......@@ -2236,7 +2203,7 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
22362203 defer if (lhs_lock) |reg| self.register_manager.unlockReg(reg);
22372204
22382205 try self.spillCompareFlagsIfOccupied();
2239 self.compare_flags_inst = null;
2206 self.condition_flags_inst = null;
22402207
22412208 // lsl dest, lhs, rhs
22422209 const dest = try self.binOp(.shl, lhs, rhs, lhs_ty, rhs_ty, null);
......@@ -2251,9 +2218,7 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
22512218 _ = try self.binOp(.cmp_eq, lhs, reconstructed, lhs_ty, lhs_ty, null);
22522219
22532220 try self.genSetStack(lhs_ty, stack_offset, dest);
2254 try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{
2255 .compare_flags_unsigned = .neq,
2256 });
2221 try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .condition_flags = .ne });
22572222
22582223 break :result MCValue{ .stack_offset = stack_offset };
22592224 } else {
......@@ -2681,8 +2646,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
26812646 .undef => unreachable,
26822647 .unreach => unreachable,
26832648 .dead => unreachable,
2684 .compare_flags_unsigned,
2685 .compare_flags_signed,
2649 .condition_flags,
26862650 .register_with_overflow,
26872651 => unreachable, // cannot hold an address
26882652 .immediate => |imm| try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm }),
......@@ -2694,7 +2658,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
26942658 switch (dst_mcv) {
26952659 .dead => unreachable,
26962660 .undef => unreachable,
2697 .compare_flags_signed, .compare_flags_unsigned => unreachable,
2661 .condition_flags => unreachable,
26982662 .register => |dst_reg| {
26992663 try self.genLdrRegister(dst_reg, addr_reg, elem_ty);
27002664 },
......@@ -2903,8 +2867,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
29032867 .undef => unreachable,
29042868 .unreach => unreachable,
29052869 .dead => unreachable,
2906 .compare_flags_unsigned,
2907 .compare_flags_signed,
2870 .condition_flags,
29082871 .register_with_overflow,
29092872 => unreachable, // cannot hold an address
29102873 .immediate => |imm| {
......@@ -3370,11 +3333,11 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
33703333 });
33713334
33723335 try self.spillCompareFlagsIfOccupied();
3373 self.compare_flags_inst = inst;
3336 self.condition_flags_inst = inst;
33743337
33753338 break :result switch (int_info.signedness) {
3376 .signed => MCValue{ .compare_flags_signed = op },
3377 .unsigned => MCValue{ .compare_flags_unsigned = op },
3339 .signed => MCValue{ .condition_flags = Condition.fromCompareOperatorSigned(op) },
3340 .unsigned => MCValue{ .condition_flags = Condition.fromCompareOperatorUnsigned(op) },
33783341 };
33793342 } else {
33803343 return self.fail("TODO AArch64 cmp for ints > 64 bits", .{});
......@@ -3434,26 +3397,13 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {
34343397
34353398fn condBr(self: *Self, condition: MCValue) !Mir.Inst.Index {
34363399 switch (condition) {
3437 .compare_flags_signed,
3438 .compare_flags_unsigned,
3439 => return try self.addInst(.{
3400 .condition_flags => |cond| return try self.addInst(.{
34403401 .tag = .b_cond,
34413402 .data = .{
34423403 .inst_cond = .{
34433404 .inst = undefined, // populated later through performReloc
3444 .cond = switch (condition) {
3445 .compare_flags_signed => |cmp_op| blk: {
3446 // Here we map to the opposite condition because the jump is to the false branch.
3447 const condition_code = Instruction.Condition.fromCompareOperatorSigned(cmp_op);
3448 break :blk condition_code.negate();
3449 },
3450 .compare_flags_unsigned => |cmp_op| blk: {
3451 // Here we map to the opposite condition because the jump is to the false branch.
3452 const condition_code = Instruction.Condition.fromCompareOperatorUnsigned(cmp_op);
3453 break :blk condition_code.negate();
3454 },
3455 else => unreachable,
3456 },
3405 // Here we map to the opposite condition because the jump is to the false branch.
3406 .cond = cond.negate(),
34573407 },
34583408 },
34593409 }),
......@@ -3503,7 +3453,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
35033453 var parent_stack = try self.stack.clone(self.gpa);
35043454 defer parent_stack.deinit(self.gpa);
35053455 const parent_registers = self.register_manager.registers;
3506 const parent_compare_flags_inst = self.compare_flags_inst;
3456 const parent_condition_flags_inst = self.condition_flags_inst;
35073457
35083458 try self.branch_stack.append(.{});
35093459 errdefer {
......@@ -3522,7 +3472,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
35223472 defer saved_then_branch.deinit(self.gpa);
35233473
35243474 self.register_manager.registers = parent_registers;
3525 self.compare_flags_inst = parent_compare_flags_inst;
3475 self.condition_flags_inst = parent_condition_flags_inst;
35263476
35273477 self.stack.deinit(self.gpa);
35283478 self.stack = parent_stack;
......@@ -3672,15 +3622,15 @@ fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
36723622 else => return self.fail("TODO implement isErr for {}", .{operand}),
36733623 }
36743624
3675 return MCValue{ .compare_flags_unsigned = .gt };
3625 return MCValue{ .condition_flags = .hi };
36763626}
36773627
36783628fn isNonErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
36793629 const is_err_result = try self.isErr(ty, operand);
36803630 switch (is_err_result) {
3681 .compare_flags_unsigned => |op| {
3682 assert(op == .gt);
3683 return MCValue{ .compare_flags_unsigned = .lte };
3631 .condition_flags => |cond| {
3632 assert(cond == .hi);
3633 return MCValue{ .condition_flags = cond.negate() };
36843634 },
36853635 .immediate => |imm| {
36863636 assert(imm == 0);
......@@ -3889,7 +3839,7 @@ fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void {
38893839 block_data.mcv = switch (operand_mcv) {
38903840 .none, .dead, .unreach => unreachable,
38913841 .register, .stack_offset, .memory => operand_mcv,
3892 .immediate => blk: {
3842 .immediate, .condition_flags => blk: {
38933843 const new_mcv = try self.allocRegOrMem(block, true);
38943844 try self.setRegOrMem(self.air.typeOfIndex(block), new_mcv, operand_mcv);
38953845 break :blk new_mcv;
......@@ -4072,8 +4022,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
40724022 else => return self.fail("TODO implement memset", .{}),
40734023 }
40744024 },
4075 .compare_flags_unsigned,
4076 .compare_flags_signed,
4025 .condition_flags,
40774026 .immediate,
40784027 .ptr_stack_offset,
40794028 => {
......@@ -4235,15 +4184,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
42354184 } },
42364185 });
42374186 },
4238 .compare_flags_unsigned,
4239 .compare_flags_signed,
4240 => |op| {
4241 const condition = switch (mcv) {
4242 .compare_flags_unsigned => Instruction.Condition.fromCompareOperatorUnsigned(op),
4243 .compare_flags_signed => Instruction.Condition.fromCompareOperatorSigned(op),
4244 else => unreachable,
4245 };
4246
4187 .condition_flags => |condition| {
42474188 _ = try self.addInst(.{
42484189 .tag = .cset,
42494190 .data = .{ .r_cond = .{