| ... | @@ -340,7 +340,7 @@ pub fn generate( | ... | @@ -340,7 +340,7 @@ pub fn generate( |
| 340 | .prev_di_line = module_fn.lbrace_line, | 340 | .prev_di_line = module_fn.lbrace_line, |
| 341 | .prev_di_column = module_fn.lbrace_column, | 341 | .prev_di_column = module_fn.lbrace_column, |
| 342 | .stack_size = mem.alignForwardGeneric(u32, function.max_end_stack, function.stack_align), | 342 | .stack_size = mem.alignForwardGeneric(u32, function.max_end_stack, function.stack_align), |
| 343 | .prologue_stack_space = call_info.stack_byte_count + function.saved_regs_stack_space, | 343 | .saved_regs_stack_space = function.saved_regs_stack_space, |
| 344 | }; | 344 | }; |
| 345 | defer emit.deinit(); | 345 | defer emit.deinit(); |
| 346 | | 346 | |
| ... | @@ -2317,6 +2317,9 @@ fn errUnionErr(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) !MCV | ... | @@ -2317,6 +2317,9 @@ fn errUnionErr(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) !MCV |
| 2317 | const err_offset = @intCast(u32, errUnionErrorOffset(payload_ty, self.target.*)); | 2317 | const err_offset = @intCast(u32, errUnionErrorOffset(payload_ty, self.target.*)); |
| 2318 | switch (error_union_mcv) { | 2318 | switch (error_union_mcv) { |
| 2319 | .register => return self.fail("TODO errUnionErr for registers", .{}), | 2319 | .register => return self.fail("TODO errUnionErr for registers", .{}), |
| | 2320 | .stack_argument_offset => |off| { |
| | 2321 | return MCValue{ .stack_argument_offset = off + err_offset }; |
| | 2322 | }, |
| 2320 | .stack_offset => |off| { | 2323 | .stack_offset => |off| { |
| 2321 | return MCValue{ .stack_offset = off - err_offset }; | 2324 | return MCValue{ .stack_offset = off - err_offset }; |
| 2322 | }, | 2325 | }, |
| ... | @@ -2351,6 +2354,9 @@ fn errUnionPayload(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) | ... | @@ -2351,6 +2354,9 @@ fn errUnionPayload(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) |
| 2351 | const payload_offset = @intCast(u32, errUnionPayloadOffset(payload_ty, self.target.*)); | 2354 | const payload_offset = @intCast(u32, errUnionPayloadOffset(payload_ty, self.target.*)); |
| 2352 | switch (error_union_mcv) { | 2355 | switch (error_union_mcv) { |
| 2353 | .register => return self.fail("TODO errUnionPayload for registers", .{}), | 2356 | .register => return self.fail("TODO errUnionPayload for registers", .{}), |
| | 2357 | .stack_argument_offset => |off| { |
| | 2358 | return MCValue{ .stack_argument_offset = off + payload_offset }; |
| | 2359 | }, |
| 2354 | .stack_offset => |off| { | 2360 | .stack_offset => |off| { |
| 2355 | return MCValue{ .stack_offset = off - payload_offset }; | 2361 | return MCValue{ .stack_offset = off - payload_offset }; |
| 2356 | }, | 2362 | }, |
| ... | @@ -3016,7 +3022,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3016,7 +3022,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 3016 | switch (mcv) { | 3022 | switch (mcv) { |
| 3017 | .dead, .unreach => unreachable, | 3023 | .dead, .unreach => unreachable, |
| 3018 | .stack_argument_offset => |off| { | 3024 | .stack_argument_offset => |off| { |
| 3019 | break :result MCValue{ .stack_argument_offset = off - struct_field_offset }; | 3025 | break :result MCValue{ .stack_argument_offset = off + struct_field_offset }; |
| 3020 | }, | 3026 | }, |
| 3021 | .stack_offset => |off| { | 3027 | .stack_offset => |off| { |
| 3022 | break :result MCValue{ .stack_offset = off - struct_field_offset }; | 3028 | break :result MCValue{ .stack_offset = off - struct_field_offset }; |
| ... | @@ -3150,6 +3156,9 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. | ... | @@ -3150,6 +3156,9 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. |
| 3150 | // saving compare flags may require a new caller-saved register | 3156 | // saving compare flags may require a new caller-saved register |
| 3151 | try self.spillCompareFlagsIfOccupied(); | 3157 | try self.spillCompareFlagsIfOccupied(); |
| 3152 | | 3158 | |
| | 3159 | // Make space for the arguments passed via the stack |
| | 3160 | self.max_end_stack += info.stack_byte_count; |
| | 3161 | |
| 3153 | for (info.args) |mc_arg, arg_i| { | 3162 | for (info.args) |mc_arg, arg_i| { |
| 3154 | const arg = args[arg_i]; | 3163 | const arg = args[arg_i]; |
| 3155 | const arg_ty = self.air.typeOf(arg); | 3164 | const arg_ty = self.air.typeOf(arg); |
| ... | @@ -3164,7 +3173,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. | ... | @@ -3164,7 +3173,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. |
| 3164 | .stack_offset => unreachable, | 3173 | .stack_offset => unreachable, |
| 3165 | .stack_argument_offset => |offset| try self.genSetStackArgument( | 3174 | .stack_argument_offset => |offset| try self.genSetStackArgument( |
| 3166 | arg_ty, | 3175 | arg_ty, |
| 3167 | info.stack_byte_count - offset, | 3176 | offset, |
| 3168 | arg_mcv, | 3177 | arg_mcv, |
| 3169 | ), | 3178 | ), |
| 3170 | else => unreachable, | 3179 | else => unreachable, |
| ... | @@ -3642,40 +3651,14 @@ fn isNonNull(self: *Self, operand: MCValue) !MCValue { | ... | @@ -3642,40 +3651,14 @@ fn isNonNull(self: *Self, operand: MCValue) !MCValue { |
| 3642 | | 3651 | |
| 3643 | fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue { | 3652 | fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue { |
| 3644 | const error_type = ty.errorUnionSet(); | 3653 | const error_type = ty.errorUnionSet(); |
| 3645 | const payload_type = ty.errorUnionPayload(); | 3654 | const error_int_type = Type.initTag(.u16); |
| 3646 | | 3655 | |
| 3647 | if (error_type.errorSetIsEmpty()) { | 3656 | if (error_type.errorSetIsEmpty()) { |
| 3648 | return MCValue{ .immediate = 0 }; // always false | 3657 | return MCValue{ .immediate = 0 }; // always false |
| 3649 | } | 3658 | } |
| 3650 | | 3659 | |
| 3651 | const err_off = errUnionErrorOffset(payload_type, self.target.*); | 3660 | const error_mcv = try self.errUnionErr(operand, ty); |
| 3652 | switch (operand) { | 3661 | _ = try self.binOp(.cmp_eq, error_mcv, .{ .immediate = 0 }, error_int_type, error_int_type, null); |
| 3653 | .stack_offset => |off| { | | |
| 3654 | const offset = off - @intCast(u32, err_off); | | |
| 3655 | const tmp_reg = try self.copyToTmpRegister(Type.anyerror, .{ .stack_offset = offset }); | | |
| 3656 | _ = try self.addInst(.{ | | |
| 3657 | .tag = .cmp_immediate, | | |
| 3658 | .data = .{ .r_imm12_sh = .{ | | |
| 3659 | .rn = tmp_reg, | | |
| 3660 | .imm12 = 0, | | |
| 3661 | } }, | | |
| 3662 | }); | | |
| 3663 | }, | | |
| 3664 | .register => |reg| { | | |
| 3665 | if (err_off > 0 or payload_type.hasRuntimeBitsIgnoreComptime()) { | | |
| 3666 | return self.fail("TODO implement isErr for register operand with payload bits", .{}); | | |
| 3667 | } | | |
| 3668 | _ = try self.addInst(.{ | | |
| 3669 | .tag = .cmp_immediate, | | |
| 3670 | .data = .{ .r_imm12_sh = .{ | | |
| 3671 | .rn = reg, | | |
| 3672 | .imm12 = 0, | | |
| 3673 | } }, | | |
| 3674 | }); | | |
| 3675 | }, | | |
| 3676 | else => return self.fail("TODO implement isErr for {}", .{operand}), | | |
| 3677 | } | | |
| 3678 | | | |
| 3679 | return MCValue{ .condition_flags = .hi }; | 3662 | return MCValue{ .condition_flags = .hi }; |
| 3680 | } | 3663 | } |
| 3681 | | 3664 | |
| ... | @@ -4174,6 +4157,15 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro | ... | @@ -4174,6 +4157,15 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 4174 | // sub src_reg, fp, #off | 4157 | // sub src_reg, fp, #off |
| 4175 | try self.genSetReg(ptr_ty, src_reg, .{ .ptr_stack_offset = off }); | 4158 | try self.genSetReg(ptr_ty, src_reg, .{ .ptr_stack_offset = off }); |
| 4176 | }, | 4159 | }, |
| | 4160 | .stack_argument_offset => |off| { |
| | 4161 | _ = try self.addInst(.{ |
| | 4162 | .tag = .ldr_ptr_stack_argument, |
| | 4163 | .data = .{ .load_store_stack = .{ |
| | 4164 | .rt = src_reg, |
| | 4165 | .offset = off, |
| | 4166 | } }, |
| | 4167 | }); |
| | 4168 | }, |
| 4177 | .memory => |addr| try self.genSetReg(Type.usize, src_reg, .{ .immediate = addr }), | 4169 | .memory => |addr| try self.genSetReg(Type.usize, src_reg, .{ .immediate = addr }), |
| 4178 | .got_load, | 4170 | .got_load, |
| 4179 | .direct_load, | 4171 | .direct_load, |
| ... | @@ -4433,7 +4425,7 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I | ... | @@ -4433,7 +4425,7 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I |
| 4433 | } | 4425 | } |
| 4434 | }, | 4426 | }, |
| 4435 | .register_with_overflow => { | 4427 | .register_with_overflow => { |
| 4436 | return self.fail("TODO implement genSetStack {}", .{mcv}); | 4428 | return self.fail("TODO implement genSetStackArgument {}", .{mcv}); |
| 4437 | }, | 4429 | }, |
| 4438 | .got_load, | 4430 | .got_load, |
| 4439 | .direct_load, | 4431 | .direct_load, |
| ... | @@ -4469,6 +4461,15 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I | ... | @@ -4469,6 +4461,15 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I |
| 4469 | // sub src_reg, fp, #off | 4461 | // sub src_reg, fp, #off |
| 4470 | try self.genSetReg(ptr_ty, src_reg, .{ .ptr_stack_offset = off }); | 4462 | try self.genSetReg(ptr_ty, src_reg, .{ .ptr_stack_offset = off }); |
| 4471 | }, | 4463 | }, |
| | 4464 | .stack_argument_offset => |off| { |
| | 4465 | _ = try self.addInst(.{ |
| | 4466 | .tag = .ldr_ptr_stack_argument, |
| | 4467 | .data = .{ .load_store_stack = .{ |
| | 4468 | .rt = src_reg, |
| | 4469 | .offset = off, |
| | 4470 | } }, |
| | 4471 | }); |
| | 4472 | }, |
| 4472 | .memory => |addr| try self.genSetReg(ptr_ty, src_reg, .{ .immediate = @intCast(u32, addr) }), | 4473 | .memory => |addr| try self.genSetReg(ptr_ty, src_reg, .{ .immediate = @intCast(u32, addr) }), |
| 4473 | .got_load, | 4474 | .got_load, |
| 4474 | .direct_load, | 4475 | .direct_load, |
| ... | @@ -4490,7 +4491,6 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I | ... | @@ -4490,7 +4491,6 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I |
| 4490 | }, | 4491 | }, |
| 4491 | }); | 4492 | }); |
| 4492 | }, | 4493 | }, |
| 4493 | .stack_argument_offset => return self.fail("TODO load {}", .{mcv}), | | |
| 4494 | else => unreachable, | 4494 | else => unreachable, |
| 4495 | } | 4495 | } |
| 4496 | | 4496 | |
| ... | @@ -4989,11 +4989,27 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { | ... | @@ -4989,11 +4989,27 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 4989 | result.stack_align = 1; | 4989 | result.stack_align = 1; |
| 4990 | return result; | 4990 | return result; |
| 4991 | }, | 4991 | }, |
| 4992 | .Unspecified, .C => { | 4992 | .C => { |
| 4993 | // ARM64 Procedure Call Standard | 4993 | // ARM64 Procedure Call Standard |
| 4994 | var ncrn: usize = 0; // Next Core Register Number | 4994 | var ncrn: usize = 0; // Next Core Register Number |
| 4995 | var nsaa: u32 = 0; // Next stacked argument address | 4995 | var nsaa: u32 = 0; // Next stacked argument address |
| 4996 | | 4996 | |
| | 4997 | if (ret_ty.zigTypeTag() == .NoReturn) { |
| | 4998 | result.return_value = .{ .unreach = {} }; |
| | 4999 | } else if (!ret_ty.hasRuntimeBitsIgnoreComptime() and !ret_ty.isError()) { |
| | 5000 | result.return_value = .{ .none = {} }; |
| | 5001 | } else { |
| | 5002 | const ret_ty_size = @intCast(u32, ret_ty.abiSize(self.target.*)); |
| | 5003 | if (ret_ty_size == 0) { |
| | 5004 | assert(ret_ty.isError()); |
| | 5005 | result.return_value = .{ .immediate = 0 }; |
| | 5006 | } else if (ret_ty_size <= 8) { |
| | 5007 | result.return_value = .{ .register = registerAlias(c_abi_int_return_regs[0], ret_ty_size) }; |
| | 5008 | } else { |
| | 5009 | return self.fail("TODO support more return types for ARM backend", .{}); |
| | 5010 | } |
| | 5011 | } |
| | 5012 | |
| 4997 | for (param_types) |ty, i| { | 5013 | for (param_types) |ty, i| { |
| 4998 | const param_size = @intCast(u32, ty.abiSize(self.target.*)); | 5014 | const param_size = @intCast(u32, ty.abiSize(self.target.*)); |
| 4999 | if (param_size == 0) { | 5015 | if (param_size == 0) { |
| ... | @@ -5027,36 +5043,52 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { | ... | @@ -5027,36 +5043,52 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 5027 | } | 5043 | } |
| 5028 | } | 5044 | } |
| 5029 | | 5045 | |
| 5030 | nsaa += param_size; | | |
| 5031 | result.args[i] = .{ .stack_argument_offset = nsaa }; | 5046 | result.args[i] = .{ .stack_argument_offset = nsaa }; |
| | 5047 | nsaa += param_size; |
| 5032 | } | 5048 | } |
| 5033 | } | 5049 | } |
| 5034 | | 5050 | |
| 5035 | result.stack_byte_count = nsaa; | 5051 | result.stack_byte_count = nsaa; |
| 5036 | result.stack_align = 16; | 5052 | result.stack_align = 16; |
| 5037 | }, | 5053 | }, |
| 5038 | else => return self.fail("TODO implement function parameters for {} on aarch64", .{cc}), | 5054 | .Unspecified => { |
| 5039 | } | 5055 | if (ret_ty.zigTypeTag() == .NoReturn) { |
| 5040 | | 5056 | result.return_value = .{ .unreach = {} }; |
| 5041 | if (ret_ty.zigTypeTag() == .NoReturn) { | 5057 | } else if (!ret_ty.hasRuntimeBitsIgnoreComptime() and !ret_ty.isError()) { |
| 5042 | result.return_value = .{ .unreach = {} }; | 5058 | result.return_value = .{ .none = {} }; |
| 5043 | } else if (!ret_ty.hasRuntimeBitsIgnoreComptime() and !ret_ty.isError()) { | | |
| 5044 | result.return_value = .{ .none = {} }; | | |
| 5045 | } else switch (cc) { | | |
| 5046 | .Naked => unreachable, | | |
| 5047 | .Unspecified, .C => { | | |
| 5048 | const ret_ty_size = @intCast(u32, ret_ty.abiSize(self.target.*)); | | |
| 5049 | if (ret_ty_size == 0) { | | |
| 5050 | assert(ret_ty.isError()); | | |
| 5051 | result.return_value = .{ .immediate = 0 }; | | |
| 5052 | } else if (ret_ty_size <= 8) { | | |
| 5053 | result.return_value = .{ .register = registerAlias(c_abi_int_return_regs[0], ret_ty_size) }; | | |
| 5054 | } else { | 5059 | } else { |
| 5055 | return self.fail("TODO support more return types for ARM backend", .{}); | 5060 | const ret_ty_size = @intCast(u32, ret_ty.abiSize(self.target.*)); |
| | 5061 | if (ret_ty_size == 0) { |
| | 5062 | assert(ret_ty.isError()); |
| | 5063 | result.return_value = .{ .immediate = 0 }; |
| | 5064 | } else if (ret_ty_size <= 8) { |
| | 5065 | result.return_value = .{ .register = registerAlias(c_abi_int_return_regs[0], ret_ty_size) }; |
| | 5066 | } else { |
| | 5067 | return self.fail("TODO support more return types for ARM backend", .{}); |
| | 5068 | } |
| 5056 | } | 5069 | } |
| | 5070 | |
| | 5071 | var stack_offset: u32 = 0; |
| | 5072 | |
| | 5073 | for (param_types) |ty, i| { |
| | 5074 | if (ty.abiSize(self.target.*) > 0) { |
| | 5075 | const param_size = @intCast(u32, ty.abiSize(self.target.*)); |
| | 5076 | const param_alignment = ty.abiAlignment(self.target.*); |
| | 5077 | |
| | 5078 | stack_offset = std.mem.alignForwardGeneric(u32, stack_offset, param_alignment); |
| | 5079 | result.args[i] = .{ .stack_argument_offset = stack_offset }; |
| | 5080 | stack_offset += param_size; |
| | 5081 | } else { |
| | 5082 | result.args[i] = .{ .none = {} }; |
| | 5083 | } |
| | 5084 | } |
| | 5085 | |
| | 5086 | result.stack_byte_count = stack_offset; |
| | 5087 | result.stack_align = 16; |
| 5057 | }, | 5088 | }, |
| 5058 | else => return self.fail("TODO implement function return values for {}", .{cc}), | 5089 | else => return self.fail("TODO implement function parameters for {} on aarch64", .{cc}), |
| 5059 | } | 5090 | } |
| | 5091 | |
| 5060 | return result; | 5092 | return result; |
| 5061 | } | 5093 | } |
| 5062 | | 5094 | |