| ... | ... | @@ -376,7 +376,7 @@ fn gen(self: *Self) !void { |
| 376 | 376 | // mov fp, sp |
| 377 | 377 | _ = try self.addInst(.{ |
| 378 | 378 | .tag = .mov_to_from_sp, |
| 379 | | .data = .{ .rr = .{ .rd = .x29, .rn = .xzr } }, |
| 379 | .data = .{ .rr = .{ .rd = .x29, .rn = .sp } }, |
| 380 | 380 | }); |
| 381 | 381 | |
| 382 | 382 | // sub sp, sp, #reloc |
| ... | ... | @@ -421,7 +421,7 @@ fn gen(self: *Self) !void { |
| 421 | 421 | if (math.cast(u12, stack_size)) |size| { |
| 422 | 422 | self.mir_instructions.set(backpatch_reloc, .{ |
| 423 | 423 | .tag = .sub_immediate, |
| 424 | | .data = .{ .rr_imm12_sh = .{ .rd = .xzr, .rn = .xzr, .imm12 = size } }, |
| 424 | .data = .{ .rr_imm12_sh = .{ .rd = .sp, .rn = .sp, .imm12 = size } }, |
| 425 | 425 | }); |
| 426 | 426 | } else |_| { |
| 427 | 427 | return self.failSymbol("TODO AArch64: allow larger stacks", .{}); |
| ... | ... | @@ -453,7 +453,7 @@ fn gen(self: *Self) !void { |
| 453 | 453 | // add sp, sp, #stack_size |
| 454 | 454 | _ = try self.addInst(.{ |
| 455 | 455 | .tag = .add_immediate, |
| 456 | | .data = .{ .rr_imm12_sh = .{ .rd = .xzr, .rn = .xzr, .imm12 = @intCast(u12, stack_size) } }, |
| 456 | .data = .{ .rr_imm12_sh = .{ .rd = .sp, .rn = .sp, .imm12 = @intCast(u12, stack_size) } }, |
| 457 | 457 | }); |
| 458 | 458 | |
| 459 | 459 | // <load other registers> |
| ... | ... | @@ -882,7 +882,8 @@ fn spillCompareFlagsIfOccupied(self: *Self) !void { |
| 882 | 882 | /// allocated. A second call to `copyToTmpRegister` may return the same register. |
| 883 | 883 | /// This can have a side effect of spilling instructions to the stack to free up a register. |
| 884 | 884 | fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register { |
| 885 | | const reg = try self.register_manager.allocReg(null); |
| 885 | const raw_reg = try self.register_manager.allocReg(null); |
| 886 | const reg = registerAlias(raw_reg, ty.abiSize(self.target.*)); |
| 886 | 887 | try self.genSetReg(ty, reg, mcv); |
| 887 | 888 | return reg; |
| 888 | 889 | } |
| ... | ... | @@ -891,7 +892,9 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register { |
| 891 | 892 | /// `reg_owner` is the instruction that gets associated with the register in the register table. |
| 892 | 893 | /// This can have a side effect of spilling instructions to the stack to free up a register. |
| 893 | 894 | fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCValue { |
| 894 | | const reg = try self.register_manager.allocReg(reg_owner); |
| 895 | const raw_reg = try self.register_manager.allocReg(reg_owner); |
| 896 | const ty = self.air.typeOfIndex(reg_owner); |
| 897 | const reg = registerAlias(raw_reg, ty.abiSize(self.target.*)); |
| 895 | 898 | try self.genSetReg(self.air.typeOfIndex(reg_owner), reg, mcv); |
| 896 | 899 | return MCValue{ .register = reg }; |
| 897 | 900 | } |
| ... | ... | @@ -1003,7 +1006,8 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { |
| 1003 | 1006 | break :blk op_reg; |
| 1004 | 1007 | } |
| 1005 | 1008 | |
| 1006 | | break :blk try self.register_manager.allocReg(null); |
| 1009 | const raw_reg = try self.register_manager.allocReg(null); |
| 1010 | break :blk raw_reg.to32(); |
| 1007 | 1011 | }; |
| 1008 | 1012 | |
| 1009 | 1013 | _ = try self.addInst(.{ |
| ... | ... | @@ -1013,7 +1017,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { |
| 1013 | 1017 | .rn = op_reg, |
| 1014 | 1018 | .imms = 0b000000, |
| 1015 | 1019 | .immr = 0b000000, |
| 1016 | | .n = 0b1, |
| 1020 | .n = 0b0, |
| 1017 | 1021 | } }, |
| 1018 | 1022 | }); |
| 1019 | 1023 | |
| ... | ... | @@ -1035,7 +1039,8 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { |
| 1035 | 1039 | break :blk op_reg; |
| 1036 | 1040 | } |
| 1037 | 1041 | |
| 1038 | | break :blk try self.register_manager.allocReg(null); |
| 1042 | const raw_reg = try self.register_manager.allocReg(null); |
| 1043 | break :blk registerAlias(raw_reg, operand_ty.abiSize(self.target.*)); |
| 1039 | 1044 | }; |
| 1040 | 1045 | |
| 1041 | 1046 | _ = try self.addInst(.{ |
| ... | ... | @@ -1124,7 +1129,8 @@ fn binOpRegister( |
| 1124 | 1129 | break :inst Air.refToIndex(bin_op.lhs).?; |
| 1125 | 1130 | } else null; |
| 1126 | 1131 | |
| 1127 | | const reg = try self.register_manager.allocReg(track_inst); |
| 1132 | const raw_reg = try self.register_manager.allocReg(track_inst); |
| 1133 | const reg = registerAlias(raw_reg, lhs_ty.abiSize(self.target.*)); |
| 1128 | 1134 | self.register_manager.freezeRegs(&.{reg}); |
| 1129 | 1135 | |
| 1130 | 1136 | if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg }); |
| ... | ... | @@ -1139,7 +1145,8 @@ fn binOpRegister( |
| 1139 | 1145 | break :inst Air.refToIndex(bin_op.rhs).?; |
| 1140 | 1146 | } else null; |
| 1141 | 1147 | |
| 1142 | | const reg = try self.register_manager.allocReg(track_inst); |
| 1148 | const raw_reg = try self.register_manager.allocReg(track_inst); |
| 1149 | const reg = registerAlias(raw_reg, rhs_ty.abiAlignment(self.target.*)); |
| 1143 | 1150 | self.register_manager.freezeRegs(&.{reg}); |
| 1144 | 1151 | |
| 1145 | 1152 | if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg }); |
| ... | ... | @@ -1156,7 +1163,8 @@ fn binOpRegister( |
| 1156 | 1163 | } else if (rhs_is_register and self.reuseOperand(inst, bin_op.rhs, 1, rhs)) { |
| 1157 | 1164 | break :blk rhs_reg; |
| 1158 | 1165 | } else { |
| 1159 | | break :blk try self.register_manager.allocReg(inst); |
| 1166 | const raw_reg = try self.register_manager.allocReg(inst); |
| 1167 | break :blk registerAlias(raw_reg, lhs_ty.abiSize(self.target.*)); |
| 1160 | 1168 | } |
| 1161 | 1169 | } else try self.register_manager.allocReg(null); |
| 1162 | 1170 | |
| ... | ... | @@ -1276,7 +1284,8 @@ fn binOpImmediate( |
| 1276 | 1284 | ).?; |
| 1277 | 1285 | } else null; |
| 1278 | 1286 | |
| 1279 | | const reg = try self.register_manager.allocReg(track_inst); |
| 1287 | const raw_reg = try self.register_manager.allocReg(track_inst); |
| 1288 | const reg = registerAlias(raw_reg, lhs_ty.abiSize(self.target.*)); |
| 1280 | 1289 | self.register_manager.freezeRegs(&.{reg}); |
| 1281 | 1290 | |
| 1282 | 1291 | if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg }); |
| ... | ... | @@ -1298,7 +1307,8 @@ fn binOpImmediate( |
| 1298 | 1307 | )) { |
| 1299 | 1308 | break :blk lhs_reg; |
| 1300 | 1309 | } else { |
| 1301 | | break :blk try self.register_manager.allocReg(inst); |
| 1310 | const raw_reg = try self.register_manager.allocReg(inst); |
| 1311 | break :blk registerAlias(raw_reg, lhs_ty.abiSize(self.target.*)); |
| 1302 | 1312 | } |
| 1303 | 1313 | } else try self.register_manager.allocReg(null), |
| 1304 | 1314 | }; |
| ... | ... | @@ -1965,7 +1975,8 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 1965 | 1975 | }, |
| 1966 | 1976 | .stack_offset => |off| { |
| 1967 | 1977 | if (elem_size <= 8) { |
| 1968 | | const tmp_reg = try self.register_manager.allocReg(null); |
| 1978 | const raw_tmp_reg = try self.register_manager.allocReg(null); |
| 1979 | const tmp_reg = registerAlias(raw_tmp_reg, elem_size); |
| 1969 | 1980 | self.register_manager.freezeRegs(&.{tmp_reg}); |
| 1970 | 1981 | defer self.register_manager.unfreezeRegs(&.{tmp_reg}); |
| 1971 | 1982 | |
| ... | ... | @@ -2001,12 +2012,8 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 2001 | 2012 | .got_load, |
| 2002 | 2013 | .direct_load, |
| 2003 | 2014 | => { |
| 2004 | | const reg = try self.register_manager.allocReg(null); |
| 2005 | | self.register_manager.freezeRegs(&.{reg}); |
| 2006 | | defer self.register_manager.unfreezeRegs(&.{reg}); |
| 2007 | | |
| 2008 | | try self.genSetReg(ptr_ty, reg, ptr); |
| 2009 | | try self.load(dst_mcv, .{ .register = reg }, ptr_ty); |
| 2015 | const addr_reg = try self.copyToTmpRegister(ptr_ty, ptr); |
| 2016 | try self.load(dst_mcv, .{ .register = addr_reg }, ptr_ty); |
| 2010 | 2017 | }, |
| 2011 | 2018 | } |
| 2012 | 2019 | } |
| ... | ... | @@ -2091,6 +2098,7 @@ fn genInlineMemcpy( |
| 2091 | 2098 | fn airLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 2092 | 2099 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2093 | 2100 | const elem_ty = self.air.typeOfIndex(inst); |
| 2101 | const elem_size = elem_ty.abiSize(self.target.*); |
| 2094 | 2102 | const result: MCValue = result: { |
| 2095 | 2103 | if (!elem_ty.hasRuntimeBits()) |
| 2096 | 2104 | break :result MCValue.none; |
| ... | ... | @@ -2101,9 +2109,12 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 2101 | 2109 | break :result MCValue.dead; |
| 2102 | 2110 | |
| 2103 | 2111 | const dst_mcv: MCValue = blk: { |
| 2104 | | if (self.reuseOperand(inst, ty_op.operand, 0, ptr)) { |
| 2112 | if (elem_size <= 8 and self.reuseOperand(inst, ty_op.operand, 0, ptr)) { |
| 2105 | 2113 | // The MCValue that holds the pointer can be re-used as the value. |
| 2106 | | break :blk ptr; |
| 2114 | break :blk switch (ptr) { |
| 2115 | .register => |r| MCValue{ .register = registerAlias(r, elem_size) }, |
| 2116 | else => ptr, |
| 2117 | }; |
| 2107 | 2118 | } else { |
| 2108 | 2119 | break :blk try self.allocRegOrMem(inst, true); |
| 2109 | 2120 | } |
| ... | ... | @@ -2209,6 +2220,8 @@ fn genStrRegister(self: *Self, value_reg: Register, addr_reg: Register, abi_size |
| 2209 | 2220 | } |
| 2210 | 2221 | |
| 2211 | 2222 | fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type) InnerError!void { |
| 2223 | const abi_size = value_ty.abiSize(self.target.*); |
| 2224 | |
| 2212 | 2225 | switch (ptr) { |
| 2213 | 2226 | .none => unreachable, |
| 2214 | 2227 | .undef => unreachable, |
| ... | ... | @@ -2226,14 +2239,14 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 2226 | 2239 | self.register_manager.freezeRegs(&.{addr_reg}); |
| 2227 | 2240 | defer self.register_manager.unfreezeRegs(&.{addr_reg}); |
| 2228 | 2241 | |
| 2229 | | const abi_size = value_ty.abiSize(self.target.*); |
| 2230 | 2242 | switch (value) { |
| 2231 | 2243 | .register => |value_reg| { |
| 2232 | 2244 | try self.genStrRegister(value_reg, addr_reg, abi_size); |
| 2233 | 2245 | }, |
| 2234 | 2246 | else => { |
| 2235 | 2247 | if (abi_size <= 8) { |
| 2236 | | const tmp_reg = try self.register_manager.allocReg(null); |
| 2248 | const raw_tmp_reg = try self.register_manager.allocReg(null); |
| 2249 | const tmp_reg = registerAlias(raw_tmp_reg, abi_size); |
| 2237 | 2250 | self.register_manager.freezeRegs(&.{tmp_reg}); |
| 2238 | 2251 | defer self.register_manager.unfreezeRegs(&.{tmp_reg}); |
| 2239 | 2252 | |
| ... | ... | @@ -3522,8 +3535,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 3522 | 3535 | .memory => |addr| { |
| 3523 | 3536 | // The value is in memory at a hard-coded address. |
| 3524 | 3537 | // If the type is a pointer, it means the pointer address is at this memory location. |
| 3525 | | try self.genSetReg(ty, reg, .{ .immediate = addr }); |
| 3526 | | try self.genLdrRegister(reg, reg, ty.abiSize(self.target.*)); |
| 3538 | try self.genSetReg(ty, reg.to64(), .{ .immediate = addr }); |
| 3539 | try self.genLdrRegister(reg, reg.to64(), ty.abiSize(self.target.*)); |
| 3527 | 3540 | }, |
| 3528 | 3541 | .stack_offset => |off| { |
| 3529 | 3542 | const abi_size = ty.abiSize(self.target.*); |
| ... | ... | @@ -3998,6 +4011,12 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 3998 | 4011 | var nsaa: u32 = 0; // Next stacked argument address |
| 3999 | 4012 | |
| 4000 | 4013 | for (param_types) |ty, i| { |
| 4014 | const param_size = @intCast(u32, ty.abiSize(self.target.*)); |
| 4015 | if (param_size == 0) { |
| 4016 | result.args[i] = .{ .none = {} }; |
| 4017 | continue; |
| 4018 | } |
| 4019 | |
| 4001 | 4020 | // We round up NCRN only for non-Apple platforms which allow the 16-byte aligned |
| 4002 | 4021 | // values to spread across odd-numbered registers. |
| 4003 | 4022 | if (ty.abiAlignment(self.target.*) == 16 and !self.target.isDarwin()) { |
| ... | ... | @@ -4005,10 +4024,9 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 4005 | 4024 | ncrn += ncrn % 2; |
| 4006 | 4025 | } |
| 4007 | 4026 | |
| 4008 | | const param_size = @intCast(u32, ty.abiSize(self.target.*)); |
| 4009 | 4027 | if (std.math.divCeil(u32, param_size, 8) catch unreachable <= 8 - ncrn) { |
| 4010 | 4028 | if (param_size <= 8) { |
| 4011 | | result.args[i] = .{ .register = c_abi_int_param_regs[ncrn] }; |
| 4029 | result.args[i] = .{ .register = registerAlias(c_abi_int_param_regs[ncrn], param_size) }; |
| 4012 | 4030 | ncrn += 1; |
| 4013 | 4031 | } else { |
| 4014 | 4032 | return self.fail("TODO MCValues with multiple registers", .{}); |
| ... | ... | @@ -4045,7 +4063,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 4045 | 4063 | .Unspecified, .C => { |
| 4046 | 4064 | const ret_ty_size = @intCast(u32, ret_ty.abiSize(self.target.*)); |
| 4047 | 4065 | if (ret_ty_size <= 8) { |
| 4048 | | result.return_value = .{ .register = c_abi_int_return_regs[0] }; |
| 4066 | result.return_value = .{ .register = registerAlias(c_abi_int_return_regs[0], ret_ty_size) }; |
| 4049 | 4067 | } else { |
| 4050 | 4068 | return self.fail("TODO support more return types for ARM backend", .{}); |
| 4051 | 4069 | } |