Commit 230bafa1ab

joachimschmidt557 <joachim.schmidt557@outlook.com>
2022-09-17 12:24:45
stage2 AArch64: simplify allocMem
1 parent 151e15e
Changed files (2)
src
arch
src/arch/aarch64/CodeGen.zig
@@ -157,40 +157,6 @@ const MCValue = union(enum) {
     condition_flags: Condition,
     /// The value is a function argument passed via the stack.
     stack_argument_offset: u32,
-
-    fn isMemory(mcv: MCValue) bool {
-        return switch (mcv) {
-            .memory, .stack_offset, .stack_argument_offset => true,
-            else => false,
-        };
-    }
-
-    fn isImmediate(mcv: MCValue) bool {
-        return switch (mcv) {
-            .immediate => true,
-            else => false,
-        };
-    }
-
-    fn isMutable(mcv: MCValue) bool {
-        return switch (mcv) {
-            .none => unreachable,
-            .unreach => unreachable,
-            .dead => unreachable,
-
-            .immediate,
-            .memory,
-            .condition_flags,
-            .ptr_stack_offset,
-            .undef,
-            .stack_argument_offset,
-            => false,
-
-            .register,
-            .stack_offset,
-            => true,
-        };
-    }
 };
 
 const Branch = struct {
@@ -416,9 +382,7 @@ fn gen(self: *Self) !void {
             const ptr_bytes = @divExact(ptr_bits, 8);
             const ret_ptr_reg = self.registerAlias(.x0, Type.usize);
 
-            const stack_offset = mem.alignForwardGeneric(u32, self.next_stack_offset, ptr_bytes) + ptr_bytes;
-            self.next_stack_offset = stack_offset;
-            self.max_end_stack = @max(self.max_end_stack, self.next_stack_offset);
+            const stack_offset = try self.allocMem(ptr_bytes, ptr_bytes, null);
 
             try self.genSetStack(Type.usize, stack_offset, MCValue{ .register = ret_ptr_reg });
             self.ret_mcv = MCValue{ .stack_offset = stack_offset };
@@ -879,17 +843,30 @@ fn addDbgInfoTypeReloc(self: *Self, ty: Type) !void {
     }
 }
 
-fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u32 {
+fn allocMem(
+    self: *Self,
+    abi_size: u32,
+    abi_align: u32,
+    maybe_inst: ?Air.Inst.Index,
+) !u32 {
+    assert(abi_size > 0);
+    assert(abi_align > 0);
+
     if (abi_align > self.stack_align)
         self.stack_align = abi_align;
+
     // TODO find a free slot instead of always appending
     const offset = mem.alignForwardGeneric(u32, self.next_stack_offset, abi_align) + abi_size;
     self.next_stack_offset = offset;
     self.max_end_stack = @max(self.max_end_stack, self.next_stack_offset);
-    try self.stack.putNoClobber(self.gpa, offset, .{
-        .inst = inst,
-        .size = abi_size,
-    });
+
+    if (maybe_inst) |inst| {
+        try self.stack.putNoClobber(self.gpa, offset, .{
+            .inst = inst,
+            .size = abi_size,
+        });
+    }
+
     return offset;
 }
 
@@ -910,40 +887,41 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 {
     };
     // TODO swap this for inst.ty.ptrAlign
     const abi_align = elem_ty.abiAlignment(self.target.*);
-    return self.allocMem(inst, abi_size, abi_align);
+
+    return self.allocMem(abi_size, abi_align, inst);
 }
 
-fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
-    const elem_ty = self.air.typeOfIndex(inst);
+fn allocRegOrMem(self: *Self, elem_ty: Type, reg_ok: bool, maybe_inst: ?Air.Inst.Index) !MCValue {
     const abi_size = math.cast(u32, elem_ty.abiSize(self.target.*)) orelse {
         const mod = self.bin_file.options.module.?;
         return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(mod)});
     };
     const abi_align = elem_ty.abiAlignment(self.target.*);
-    if (abi_align > self.stack_align)
-        self.stack_align = abi_align;
 
     if (reg_ok) {
         // Make sure the type can fit in a register before we try to allocate one.
         if (abi_size <= 8) {
-            if (self.register_manager.tryAllocReg(inst, gp)) |reg| {
+            if (self.register_manager.tryAllocReg(maybe_inst, gp)) |reg| {
                 return MCValue{ .register = self.registerAlias(reg, elem_ty) };
             }
         }
     }
-    const stack_offset = try self.allocMem(inst, abi_size, abi_align);
+
+    const stack_offset = try self.allocMem(abi_size, abi_align, maybe_inst);
     return MCValue{ .stack_offset = stack_offset };
 }
 
 pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void {
-    const stack_mcv = try self.allocRegOrMem(inst, false);
+    const stack_mcv = try self.allocRegOrMem(self.air.typeOfIndex(inst), false, inst);
     log.debug("spilling {d} to stack mcv {any}", .{ inst, stack_mcv });
+
     const reg_mcv = self.getResolvedInstValue(inst);
     switch (reg_mcv) {
         .register => |r| assert(reg.id() == r.id()),
         .register_with_overflow => |rwo| assert(rwo.reg.id() == reg.id()),
         else => unreachable, // not a register
     }
+
     const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
     try branch.inst_table.put(self.gpa, inst, stack_mcv);
     try self.genSetStack(self.air.typeOfIndex(inst), stack_mcv.stack_offset, reg_mcv);
@@ -953,10 +931,11 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void
 /// occupied
 fn spillCompareFlagsIfOccupied(self: *Self) !void {
     if (self.condition_flags_inst) |inst_to_save| {
+        const ty = self.air.typeOfIndex(inst_to_save);
         const mcv = self.getResolvedInstValue(inst_to_save);
         const new_mcv = switch (mcv) {
-            .condition_flags => try self.allocRegOrMem(inst_to_save, true),
-            .register_with_overflow => try self.allocRegOrMem(inst_to_save, false),
+            .condition_flags => try self.allocRegOrMem(ty, true, inst_to_save),
+            .register_with_overflow => try self.allocRegOrMem(ty, false, inst_to_save),
             else => unreachable, // mcv doesn't occupy the compare flags
         };
 
@@ -1046,14 +1025,14 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
         };
 
         if (dest_info.bits > operand_info.bits) {
-            const dest_mcv = try self.allocRegOrMem(inst, true);
+            const dest_mcv = try self.allocRegOrMem(dest_ty, true, inst);
             try self.setRegOrMem(self.air.typeOfIndex(inst), dest_mcv, truncated);
             break :result dest_mcv;
         } else {
             if (self.reuseOperand(inst, operand, 0, truncated)) {
                 break :result truncated;
             } else {
-                const dest_mcv = try self.allocRegOrMem(inst, true);
+                const dest_mcv = try self.allocRegOrMem(dest_ty, true, inst);
                 try self.setRegOrMem(self.air.typeOfIndex(inst), dest_mcv, truncated);
                 break :result dest_mcv;
             }
@@ -1278,7 +1257,7 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {
         const ptr_bits = self.target.cpu.arch.ptrBitWidth();
         const ptr_bytes = @divExact(ptr_bits, 8);
 
-        const stack_offset = try self.allocMem(inst, ptr_bytes * 2, ptr_bytes * 2);
+        const stack_offset = try self.allocMem(ptr_bytes * 2, ptr_bytes * 2, inst);
         try self.genSetStack(ptr_ty, stack_offset, ptr);
         try self.genSetStack(len_ty, stack_offset - ptr_bytes, len);
         break :result MCValue{ .stack_offset = stack_offset };
@@ -2049,7 +2028,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {
                 const int_info = lhs_ty.intInfo(self.target.*);
                 switch (int_info.bits) {
                     1...31, 33...63 => {
-                        const stack_offset = try self.allocMem(inst, tuple_size, tuple_align);
+                        const stack_offset = try self.allocMem(tuple_size, tuple_align, inst);
 
                         try self.spillCompareFlagsIfOccupied();
                         self.condition_flags_inst = null;
@@ -2164,7 +2143,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
                 const int_info = lhs_ty.intInfo(self.target.*);
 
                 if (int_info.bits <= 32) {
-                    const stack_offset = try self.allocMem(inst, tuple_size, tuple_align);
+                    const stack_offset = try self.allocMem(tuple_size, tuple_align, inst);
 
                     try self.spillCompareFlagsIfOccupied();
                     self.condition_flags_inst = null;
@@ -2220,7 +2199,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
 
                     break :result MCValue{ .stack_offset = stack_offset };
                 } else if (int_info.bits <= 64) {
-                    const stack_offset = try self.allocMem(inst, tuple_size, tuple_align);
+                    const stack_offset = try self.allocMem(tuple_size, tuple_align, inst);
 
                     try self.spillCompareFlagsIfOccupied();
                     self.condition_flags_inst = null;
@@ -2424,7 +2403,7 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
             .Int => {
                 const int_info = lhs_ty.intInfo(self.target.*);
                 if (int_info.bits <= 64) {
-                    const stack_offset = try self.allocMem(inst, tuple_size, tuple_align);
+                    const stack_offset = try self.allocMem(tuple_size, tuple_align, inst);
 
                     const lhs_lock: ?RegisterLock = if (lhs == .register)
                         self.register_manager.lockRegAssumeUnused(lhs.register)
@@ -2745,7 +2724,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
                 const base_reg_lock = self.register_manager.lockRegAssumeUnused(base_reg);
                 defer self.register_manager.unlockReg(base_reg_lock);
 
-                const dest = try self.allocRegOrMem(inst, true);
+                const dest = try self.allocRegOrMem(elem_ty, true, inst);
                 const addr = try self.binOp(.ptr_add, base_mcv, index_mcv, slice_ptr_field_type, Type.usize, null);
                 try self.load(dest, addr, slice_ptr_field_type);
 
@@ -3058,7 +3037,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
                     else => ptr,
                 };
             } else {
-                break :blk try self.allocRegOrMem(inst, true);
+                break :blk try self.allocRegOrMem(elem_ty, true, inst);
             }
         };
         try self.load(dst_mcv, ptr, self.air.typeOf(ty_op.operand));
@@ -3334,7 +3313,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
                 return self.fail("type '{}' too big to fit into stack frame", .{ty.fmt(mod)});
             };
             const abi_align = ty.abiAlignment(self.target.*);
-            const stack_offset = try self.allocMem(inst, abi_size, abi_align);
+            const stack_offset = try self.allocMem(abi_size, abi_align, inst);
             try self.genSetStack(ty, stack_offset, MCValue{ .register = reg });
 
             break :blk MCValue{ .stack_offset = stack_offset };
@@ -3412,7 +3391,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
         const ret_ty = fn_ty.fnReturnType();
         const ret_abi_size = @intCast(u32, ret_ty.abiSize(self.target.*));
         const ret_abi_align = @intCast(u32, ret_ty.abiAlignment(self.target.*));
-        const stack_offset = try self.allocMem(inst, ret_abi_size, ret_abi_align);
+        const stack_offset = try self.allocMem(ret_abi_size, ret_abi_align, inst);
 
         const ret_ptr_reg = self.registerAlias(.x0, Type.usize);
 
@@ -3638,14 +3617,7 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void {
                 const abi_size = @intCast(u32, ret_ty.abiSize(self.target.*));
                 const abi_align = ret_ty.abiAlignment(self.target.*);
 
-                // This is essentially allocMem without the
-                // instruction tracking
-                if (abi_align > self.stack_align)
-                    self.stack_align = abi_align;
-                // TODO find a free slot instead of always appending
-                const offset = mem.alignForwardGeneric(u32, self.next_stack_offset, abi_align) + abi_size;
-                self.next_stack_offset = offset;
-                self.max_end_stack = @max(self.max_end_stack, self.next_stack_offset);
+                const offset = try self.allocMem(abi_size, abi_align, null);
 
                 const tmp_mcv = MCValue{ .stack_offset = offset };
                 try self.load(tmp_mcv, ptr, ptr_ty);
@@ -3993,15 +3965,12 @@ fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void {
     const un_op = self.air.instructions.items(.data)[inst].un_op;
     const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
         const operand_ptr = try self.resolveInst(un_op);
-        const operand: MCValue = blk: {
-            if (self.reuseOperand(inst, un_op, 0, operand_ptr)) {
-                // The MCValue that holds the pointer can be re-used as the value.
-                break :blk operand_ptr;
-            } else {
-                break :blk try self.allocRegOrMem(inst, true);
-            }
-        };
-        try self.load(operand, operand_ptr, self.air.typeOf(un_op));
+        const ptr_ty = self.air.typeOf(un_op);
+        const elem_ty = ptr_ty.elemType();
+
+        const operand = try self.allocRegOrMem(elem_ty, true, null);
+        try self.load(operand, operand_ptr, ptr_ty);
+
         break :result try self.isNull(operand);
     };
     return self.finishAir(inst, result, .{ un_op, .none, .none });
@@ -4020,15 +3989,12 @@ fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void {
     const un_op = self.air.instructions.items(.data)[inst].un_op;
     const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
         const operand_ptr = try self.resolveInst(un_op);
-        const operand: MCValue = blk: {
-            if (self.reuseOperand(inst, un_op, 0, operand_ptr)) {
-                // The MCValue that holds the pointer can be re-used as the value.
-                break :blk operand_ptr;
-            } else {
-                break :blk try self.allocRegOrMem(inst, true);
-            }
-        };
-        try self.load(operand, operand_ptr, self.air.typeOf(un_op));
+        const ptr_ty = self.air.typeOf(un_op);
+        const elem_ty = ptr_ty.elemType();
+
+        const operand = try self.allocRegOrMem(elem_ty, true, null);
+        try self.load(operand, operand_ptr, ptr_ty);
+
         break :result try self.isNonNull(operand);
     };
     return self.finishAir(inst, result, .{ un_op, .none, .none });
@@ -4049,16 +4015,12 @@ fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void {
     const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
         const operand_ptr = try self.resolveInst(un_op);
         const ptr_ty = self.air.typeOf(un_op);
-        const operand: MCValue = blk: {
-            if (self.reuseOperand(inst, un_op, 0, operand_ptr)) {
-                // The MCValue that holds the pointer can be re-used as the value.
-                break :blk operand_ptr;
-            } else {
-                break :blk try self.allocRegOrMem(inst, true);
-            }
-        };
-        try self.load(operand, operand_ptr, self.air.typeOf(un_op));
-        break :result try self.isErr(ptr_ty.elemType(), operand);
+        const elem_ty = ptr_ty.elemType();
+
+        const operand = try self.allocRegOrMem(elem_ty, true, null);
+        try self.load(operand, operand_ptr, ptr_ty);
+
+        break :result try self.isErr(elem_ty, operand);
     };
     return self.finishAir(inst, result, .{ un_op, .none, .none });
 }
@@ -4078,16 +4040,12 @@ fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void {
     const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
         const operand_ptr = try self.resolveInst(un_op);
         const ptr_ty = self.air.typeOf(un_op);
-        const operand: MCValue = blk: {
-            if (self.reuseOperand(inst, un_op, 0, operand_ptr)) {
-                // The MCValue that holds the pointer can be re-used as the value.
-                break :blk operand_ptr;
-            } else {
-                break :blk try self.allocRegOrMem(inst, true);
-            }
-        };
-        try self.load(operand, operand_ptr, self.air.typeOf(un_op));
-        break :result try self.isNonErr(ptr_ty.elemType(), operand);
+        const elem_ty = ptr_ty.elemType();
+
+        const operand = try self.allocRegOrMem(elem_ty, true, null);
+        try self.load(operand, operand_ptr, ptr_ty);
+
+        break :result try self.isNonErr(elem_ty, operand);
     };
     return self.finishAir(inst, result, .{ un_op, .none, .none });
 }
@@ -4180,7 +4138,7 @@ fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void {
                 .none, .dead, .unreach => unreachable,
                 .register, .stack_offset, .memory => operand_mcv,
                 .immediate, .stack_argument_offset, .condition_flags => blk: {
-                    const new_mcv = try self.allocRegOrMem(block, true);
+                    const new_mcv = try self.allocRegOrMem(self.air.typeOfIndex(block), true, block);
                     try self.setRegOrMem(self.air.typeOfIndex(block), new_mcv, operand_mcv);
                     break :blk new_mcv;
                 },
@@ -4837,7 +4795,7 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void {
         const ptr_bits = self.target.cpu.arch.ptrBitWidth();
         const ptr_bytes = @divExact(ptr_bits, 8);
 
-        const stack_offset = try self.allocMem(inst, ptr_bytes * 2, ptr_bytes * 2);
+        const stack_offset = try self.allocMem(ptr_bytes * 2, ptr_bytes * 2, inst);
         try self.genSetStack(ptr_ty, stack_offset, ptr);
         try self.genSetStack(Type.initTag(.usize), stack_offset - ptr_bytes, .{ .immediate = array_len });
         break :result MCValue{ .stack_offset = stack_offset };
src/arch/aarch64/Mir.zig
@@ -432,7 +432,7 @@ pub const Inst = struct {
             rn: Register,
             offset: bits.Instruction.LoadStoreOffsetRegister,
         },
-        /// A registers and a stack offset
+        /// A register and a stack offset
         ///
         /// Used by e.g. str_stack
         load_store_stack: struct {
@@ -464,10 +464,6 @@ pub const Inst = struct {
             line: u32,
             column: u32,
         },
-        load_memory: struct {
-            register: u32,
-            addr: u32,
-        },
     };
 
     // Make sure we don't accidentally make instructions bigger than expected.