authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-09-17 12:24:45+02:00
committergravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-10-20 16:14:52+02:00
log230bafa1abb25192500a84d2cccf7e25f67eb7ec
tree13537aa5c8565a77b36c66bfec3d746afbf691da
parent151e15e444cc691546bc30646967ef08dbcc073f
signaturelock-open Commit is signed but in an unrecognized format.

stage2 AArch64: simplify allocMem


2 files changed, 70 insertions(+), 116 deletions(-)

src/arch/aarch64/CodeGen.zig+69-111
......@@ -157,40 +157,6 @@ const MCValue = union(enum) {
157157 condition_flags: Condition,
158158 /// The value is a function argument passed via the stack.
159159 stack_argument_offset: u32,
160
161 fn isMemory(mcv: MCValue) bool {
162 return switch (mcv) {
163 .memory, .stack_offset, .stack_argument_offset => true,
164 else => false,
165 };
166 }
167
168 fn isImmediate(mcv: MCValue) bool {
169 return switch (mcv) {
170 .immediate => true,
171 else => false,
172 };
173 }
174
175 fn isMutable(mcv: MCValue) bool {
176 return switch (mcv) {
177 .none => unreachable,
178 .unreach => unreachable,
179 .dead => unreachable,
180
181 .immediate,
182 .memory,
183 .condition_flags,
184 .ptr_stack_offset,
185 .undef,
186 .stack_argument_offset,
187 => false,
188
189 .register,
190 .stack_offset,
191 => true,
192 };
193 }
194160};
195161
196162const Branch = struct {
......@@ -416,9 +382,7 @@ fn gen(self: *Self) !void {
416382 const ptr_bytes = @divExact(ptr_bits, 8);
417383 const ret_ptr_reg = self.registerAlias(.x0, Type.usize);
418384
419 const stack_offset = mem.alignForwardGeneric(u32, self.next_stack_offset, ptr_bytes) + ptr_bytes;
420 self.next_stack_offset = stack_offset;
421 self.max_end_stack = @max(self.max_end_stack, self.next_stack_offset);
385 const stack_offset = try self.allocMem(ptr_bytes, ptr_bytes, null);
422386
423387 try self.genSetStack(Type.usize, stack_offset, MCValue{ .register = ret_ptr_reg });
424388 self.ret_mcv = MCValue{ .stack_offset = stack_offset };
......@@ -879,17 +843,30 @@ fn addDbgInfoTypeReloc(self: *Self, ty: Type) !void {
879843 }
880844}
881845
882fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u32 {
846fn allocMem(
847 self: *Self,
848 abi_size: u32,
849 abi_align: u32,
850 maybe_inst: ?Air.Inst.Index,
851) !u32 {
852 assert(abi_size > 0);
853 assert(abi_align > 0);
854
883855 if (abi_align > self.stack_align)
884856 self.stack_align = abi_align;
857
885858 // TODO find a free slot instead of always appending
886859 const offset = mem.alignForwardGeneric(u32, self.next_stack_offset, abi_align) + abi_size;
887860 self.next_stack_offset = offset;
888861 self.max_end_stack = @max(self.max_end_stack, self.next_stack_offset);
889 try self.stack.putNoClobber(self.gpa, offset, .{
890 .inst = inst,
891 .size = abi_size,
892 });
862
863 if (maybe_inst) |inst| {
864 try self.stack.putNoClobber(self.gpa, offset, .{
865 .inst = inst,
866 .size = abi_size,
867 });
868 }
869
893870 return offset;
894871}
895872
......@@ -910,40 +887,41 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 {
910887 };
911888 // TODO swap this for inst.ty.ptrAlign
912889 const abi_align = elem_ty.abiAlignment(self.target.*);
913 return self.allocMem(inst, abi_size, abi_align);
890
891 return self.allocMem(abi_size, abi_align, inst);
914892}
915893
916fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
917 const elem_ty = self.air.typeOfIndex(inst);
894fn allocRegOrMem(self: *Self, elem_ty: Type, reg_ok: bool, maybe_inst: ?Air.Inst.Index) !MCValue {
918895 const abi_size = math.cast(u32, elem_ty.abiSize(self.target.*)) orelse {
919896 const mod = self.bin_file.options.module.?;
920897 return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(mod)});
921898 };
922899 const abi_align = elem_ty.abiAlignment(self.target.*);
923 if (abi_align > self.stack_align)
924 self.stack_align = abi_align;
925900
926901 if (reg_ok) {
927902 // Make sure the type can fit in a register before we try to allocate one.
928903 if (abi_size <= 8) {
929 if (self.register_manager.tryAllocReg(inst, gp)) |reg| {
904 if (self.register_manager.tryAllocReg(maybe_inst, gp)) |reg| {
930905 return MCValue{ .register = self.registerAlias(reg, elem_ty) };
931906 }
932907 }
933908 }
934 const stack_offset = try self.allocMem(inst, abi_size, abi_align);
909
910 const stack_offset = try self.allocMem(abi_size, abi_align, maybe_inst);
935911 return MCValue{ .stack_offset = stack_offset };
936912}
937913
938914pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void {
939 const stack_mcv = try self.allocRegOrMem(inst, false);
915 const stack_mcv = try self.allocRegOrMem(self.air.typeOfIndex(inst), false, inst);
940916 log.debug("spilling {d} to stack mcv {any}", .{ inst, stack_mcv });
917
941918 const reg_mcv = self.getResolvedInstValue(inst);
942919 switch (reg_mcv) {
943920 .register => |r| assert(reg.id() == r.id()),
944921 .register_with_overflow => |rwo| assert(rwo.reg.id() == reg.id()),
945922 else => unreachable, // not a register
946923 }
924
947925 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
948926 try branch.inst_table.put(self.gpa, inst, stack_mcv);
949927 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
953931/// occupied
954932fn spillCompareFlagsIfOccupied(self: *Self) !void {
955933 if (self.condition_flags_inst) |inst_to_save| {
934 const ty = self.air.typeOfIndex(inst_to_save);
956935 const mcv = self.getResolvedInstValue(inst_to_save);
957936 const new_mcv = switch (mcv) {
958 .condition_flags => try self.allocRegOrMem(inst_to_save, true),
959 .register_with_overflow => try self.allocRegOrMem(inst_to_save, false),
937 .condition_flags => try self.allocRegOrMem(ty, true, inst_to_save),
938 .register_with_overflow => try self.allocRegOrMem(ty, false, inst_to_save),
960939 else => unreachable, // mcv doesn't occupy the compare flags
961940 };
962941
......@@ -1046,14 +1025,14 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
10461025 };
10471026
10481027 if (dest_info.bits > operand_info.bits) {
1049 const dest_mcv = try self.allocRegOrMem(inst, true);
1028 const dest_mcv = try self.allocRegOrMem(dest_ty, true, inst);
10501029 try self.setRegOrMem(self.air.typeOfIndex(inst), dest_mcv, truncated);
10511030 break :result dest_mcv;
10521031 } else {
10531032 if (self.reuseOperand(inst, operand, 0, truncated)) {
10541033 break :result truncated;
10551034 } else {
1056 const dest_mcv = try self.allocRegOrMem(inst, true);
1035 const dest_mcv = try self.allocRegOrMem(dest_ty, true, inst);
10571036 try self.setRegOrMem(self.air.typeOfIndex(inst), dest_mcv, truncated);
10581037 break :result dest_mcv;
10591038 }
......@@ -1278,7 +1257,7 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {
12781257 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
12791258 const ptr_bytes = @divExact(ptr_bits, 8);
12801259
1281 const stack_offset = try self.allocMem(inst, ptr_bytes * 2, ptr_bytes * 2);
1260 const stack_offset = try self.allocMem(ptr_bytes * 2, ptr_bytes * 2, inst);
12821261 try self.genSetStack(ptr_ty, stack_offset, ptr);
12831262 try self.genSetStack(len_ty, stack_offset - ptr_bytes, len);
12841263 break :result MCValue{ .stack_offset = stack_offset };
......@@ -2049,7 +2028,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {
20492028 const int_info = lhs_ty.intInfo(self.target.*);
20502029 switch (int_info.bits) {
20512030 1...31, 33...63 => {
2052 const stack_offset = try self.allocMem(inst, tuple_size, tuple_align);
2031 const stack_offset = try self.allocMem(tuple_size, tuple_align, inst);
20532032
20542033 try self.spillCompareFlagsIfOccupied();
20552034 self.condition_flags_inst = null;
......@@ -2164,7 +2143,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
21642143 const int_info = lhs_ty.intInfo(self.target.*);
21652144
21662145 if (int_info.bits <= 32) {
2167 const stack_offset = try self.allocMem(inst, tuple_size, tuple_align);
2146 const stack_offset = try self.allocMem(tuple_size, tuple_align, inst);
21682147
21692148 try self.spillCompareFlagsIfOccupied();
21702149 self.condition_flags_inst = null;
......@@ -2220,7 +2199,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
22202199
22212200 break :result MCValue{ .stack_offset = stack_offset };
22222201 } else if (int_info.bits <= 64) {
2223 const stack_offset = try self.allocMem(inst, tuple_size, tuple_align);
2202 const stack_offset = try self.allocMem(tuple_size, tuple_align, inst);
22242203
22252204 try self.spillCompareFlagsIfOccupied();
22262205 self.condition_flags_inst = null;
......@@ -2424,7 +2403,7 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
24242403 .Int => {
24252404 const int_info = lhs_ty.intInfo(self.target.*);
24262405 if (int_info.bits <= 64) {
2427 const stack_offset = try self.allocMem(inst, tuple_size, tuple_align);
2406 const stack_offset = try self.allocMem(tuple_size, tuple_align, inst);
24282407
24292408 const lhs_lock: ?RegisterLock = if (lhs == .register)
24302409 self.register_manager.lockRegAssumeUnused(lhs.register)
......@@ -2745,7 +2724,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
27452724 const base_reg_lock = self.register_manager.lockRegAssumeUnused(base_reg);
27462725 defer self.register_manager.unlockReg(base_reg_lock);
27472726
2748 const dest = try self.allocRegOrMem(inst, true);
2727 const dest = try self.allocRegOrMem(elem_ty, true, inst);
27492728 const addr = try self.binOp(.ptr_add, base_mcv, index_mcv, slice_ptr_field_type, Type.usize, null);
27502729 try self.load(dest, addr, slice_ptr_field_type);
27512730
......@@ -3058,7 +3037,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
30583037 else => ptr,
30593038 };
30603039 } else {
3061 break :blk try self.allocRegOrMem(inst, true);
3040 break :blk try self.allocRegOrMem(elem_ty, true, inst);
30623041 }
30633042 };
30643043 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 {
33343313 return self.fail("type '{}' too big to fit into stack frame", .{ty.fmt(mod)});
33353314 };
33363315 const abi_align = ty.abiAlignment(self.target.*);
3337 const stack_offset = try self.allocMem(inst, abi_size, abi_align);
3316 const stack_offset = try self.allocMem(abi_size, abi_align, inst);
33383317 try self.genSetStack(ty, stack_offset, MCValue{ .register = reg });
33393318
33403319 break :blk MCValue{ .stack_offset = stack_offset };
......@@ -3412,7 +3391,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
34123391 const ret_ty = fn_ty.fnReturnType();
34133392 const ret_abi_size = @intCast(u32, ret_ty.abiSize(self.target.*));
34143393 const ret_abi_align = @intCast(u32, ret_ty.abiAlignment(self.target.*));
3415 const stack_offset = try self.allocMem(inst, ret_abi_size, ret_abi_align);
3394 const stack_offset = try self.allocMem(ret_abi_size, ret_abi_align, inst);
34163395
34173396 const ret_ptr_reg = self.registerAlias(.x0, Type.usize);
34183397
......@@ -3638,14 +3617,7 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void {
36383617 const abi_size = @intCast(u32, ret_ty.abiSize(self.target.*));
36393618 const abi_align = ret_ty.abiAlignment(self.target.*);
36403619
3641 // This is essentially allocMem without the
3642 // instruction tracking
3643 if (abi_align > self.stack_align)
3644 self.stack_align = abi_align;
3645 // TODO find a free slot instead of always appending
3646 const offset = mem.alignForwardGeneric(u32, self.next_stack_offset, abi_align) + abi_size;
3647 self.next_stack_offset = offset;
3648 self.max_end_stack = @max(self.max_end_stack, self.next_stack_offset);
3620 const offset = try self.allocMem(abi_size, abi_align, null);
36493621
36503622 const tmp_mcv = MCValue{ .stack_offset = offset };
36513623 try self.load(tmp_mcv, ptr, ptr_ty);
......@@ -3993,15 +3965,12 @@ fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void {
39933965 const un_op = self.air.instructions.items(.data)[inst].un_op;
39943966 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
39953967 const operand_ptr = try self.resolveInst(un_op);
3996 const operand: MCValue = blk: {
3997 if (self.reuseOperand(inst, un_op, 0, operand_ptr)) {
3998 // The MCValue that holds the pointer can be re-used as the value.
3999 break :blk operand_ptr;
4000 } else {
4001 break :blk try self.allocRegOrMem(inst, true);
4002 }
4003 };
4004 try self.load(operand, operand_ptr, self.air.typeOf(un_op));
3968 const ptr_ty = self.air.typeOf(un_op);
3969 const elem_ty = ptr_ty.elemType();
3970
3971 const operand = try self.allocRegOrMem(elem_ty, true, null);
3972 try self.load(operand, operand_ptr, ptr_ty);
3973
40053974 break :result try self.isNull(operand);
40063975 };
40073976 return self.finishAir(inst, result, .{ un_op, .none, .none });
......@@ -4020,15 +3989,12 @@ fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void {
40203989 const un_op = self.air.instructions.items(.data)[inst].un_op;
40213990 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
40223991 const operand_ptr = try self.resolveInst(un_op);
4023 const operand: MCValue = blk: {
4024 if (self.reuseOperand(inst, un_op, 0, operand_ptr)) {
4025 // The MCValue that holds the pointer can be re-used as the value.
4026 break :blk operand_ptr;
4027 } else {
4028 break :blk try self.allocRegOrMem(inst, true);
4029 }
4030 };
4031 try self.load(operand, operand_ptr, self.air.typeOf(un_op));
3992 const ptr_ty = self.air.typeOf(un_op);
3993 const elem_ty = ptr_ty.elemType();
3994
3995 const operand = try self.allocRegOrMem(elem_ty, true, null);
3996 try self.load(operand, operand_ptr, ptr_ty);
3997
40323998 break :result try self.isNonNull(operand);
40333999 };
40344000 return self.finishAir(inst, result, .{ un_op, .none, .none });
......@@ -4049,16 +4015,12 @@ fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void {
40494015 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
40504016 const operand_ptr = try self.resolveInst(un_op);
40514017 const ptr_ty = self.air.typeOf(un_op);
4052 const operand: MCValue = blk: {
4053 if (self.reuseOperand(inst, un_op, 0, operand_ptr)) {
4054 // The MCValue that holds the pointer can be re-used as the value.
4055 break :blk operand_ptr;
4056 } else {
4057 break :blk try self.allocRegOrMem(inst, true);
4058 }
4059 };
4060 try self.load(operand, operand_ptr, self.air.typeOf(un_op));
4061 break :result try self.isErr(ptr_ty.elemType(), operand);
4018 const elem_ty = ptr_ty.elemType();
4019
4020 const operand = try self.allocRegOrMem(elem_ty, true, null);
4021 try self.load(operand, operand_ptr, ptr_ty);
4022
4023 break :result try self.isErr(elem_ty, operand);
40624024 };
40634025 return self.finishAir(inst, result, .{ un_op, .none, .none });
40644026}
......@@ -4078,16 +4040,12 @@ fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void {
40784040 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
40794041 const operand_ptr = try self.resolveInst(un_op);
40804042 const ptr_ty = self.air.typeOf(un_op);
4081 const operand: MCValue = blk: {
4082 if (self.reuseOperand(inst, un_op, 0, operand_ptr)) {
4083 // The MCValue that holds the pointer can be re-used as the value.
4084 break :blk operand_ptr;
4085 } else {
4086 break :blk try self.allocRegOrMem(inst, true);
4087 }
4088 };
4089 try self.load(operand, operand_ptr, self.air.typeOf(un_op));
4090 break :result try self.isNonErr(ptr_ty.elemType(), operand);
4043 const elem_ty = ptr_ty.elemType();
4044
4045 const operand = try self.allocRegOrMem(elem_ty, true, null);
4046 try self.load(operand, operand_ptr, ptr_ty);
4047
4048 break :result try self.isNonErr(elem_ty, operand);
40914049 };
40924050 return self.finishAir(inst, result, .{ un_op, .none, .none });
40934051}
......@@ -4180,7 +4138,7 @@ fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void {
41804138 .none, .dead, .unreach => unreachable,
41814139 .register, .stack_offset, .memory => operand_mcv,
41824140 .immediate, .stack_argument_offset, .condition_flags => blk: {
4183 const new_mcv = try self.allocRegOrMem(block, true);
4141 const new_mcv = try self.allocRegOrMem(self.air.typeOfIndex(block), true, block);
41844142 try self.setRegOrMem(self.air.typeOfIndex(block), new_mcv, operand_mcv);
41854143 break :blk new_mcv;
41864144 },
......@@ -4837,7 +4795,7 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void {
48374795 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
48384796 const ptr_bytes = @divExact(ptr_bits, 8);
48394797
4840 const stack_offset = try self.allocMem(inst, ptr_bytes * 2, ptr_bytes * 2);
4798 const stack_offset = try self.allocMem(ptr_bytes * 2, ptr_bytes * 2, inst);
48414799 try self.genSetStack(ptr_ty, stack_offset, ptr);
48424800 try self.genSetStack(Type.initTag(.usize), stack_offset - ptr_bytes, .{ .immediate = array_len });
48434801 break :result MCValue{ .stack_offset = stack_offset };
src/arch/aarch64/Mir.zig+1-5
......@@ -432,7 +432,7 @@ pub const Inst = struct {
432432 rn: Register,
433433 offset: bits.Instruction.LoadStoreOffsetRegister,
434434 },
435 /// A registers and a stack offset
435 /// A register and a stack offset
436436 ///
437437 /// Used by e.g. str_stack
438438 load_store_stack: struct {
......@@ -464,10 +464,6 @@ pub const Inst = struct {
464464 line: u32,
465465 column: u32,
466466 },
467 load_memory: struct {
468 register: u32,
469 addr: u32,
470 },
471467 };
472468
473469 // Make sure we don't accidentally make instructions bigger than expected.