| ... | @@ -4204,7 +4204,6 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4204,7 +4204,6 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void { |
| 4204 | }, | 4204 | }, |
| 4205 | .stack_offset => { | 4205 | .stack_offset => { |
| 4206 | const reg = try self.copyToTmpRegister(Type.usize, self.ret_mcv); | 4206 | const reg = try self.copyToTmpRegister(Type.usize, self.ret_mcv); |
| 4207 | log.warn("REG = {}", .{reg}); | | |
| 4208 | const reg_lock = self.register_manager.lockRegAssumeUnused(reg); | 4207 | const reg_lock = self.register_manager.lockRegAssumeUnused(reg); |
| 4209 | defer self.register_manager.unlockReg(reg_lock); | 4208 | defer self.register_manager.unlockReg(reg_lock); |
| 4210 | | 4209 | |
| ... | @@ -7129,11 +7128,12 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { | ... | @@ -7129,11 +7128,12 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 7129 | result.stack_align = 1; | 7128 | result.stack_align = 1; |
| 7130 | return result; | 7129 | return result; |
| 7131 | }, | 7130 | }, |
| 7132 | .Unspecified, .C => { | 7131 | .C => { |
| 7133 | // Return values | 7132 | // Return values |
| 7134 | if (ret_ty.zigTypeTag() == .NoReturn) { | 7133 | if (ret_ty.zigTypeTag() == .NoReturn) { |
| 7135 | result.return_value = .{ .unreach = {} }; | 7134 | result.return_value = .{ .unreach = {} }; |
| 7136 | } else if (!ret_ty.hasRuntimeBitsIgnoreComptime() and !ret_ty.isError()) { | 7135 | } else if (!ret_ty.hasRuntimeBitsIgnoreComptime() and !ret_ty.isError()) { |
| | 7136 | // TODO: is this even possible for C calling convention? |
| 7137 | result.return_value = .{ .none = {} }; | 7137 | result.return_value = .{ .none = {} }; |
| 7138 | } else { | 7138 | } else { |
| 7139 | const ret_ty_size = @intCast(u32, ret_ty.abiSize(self.target.*)); | 7139 | const ret_ty_size = @intCast(u32, ret_ty.abiSize(self.target.*)); |
| ... | @@ -7144,81 +7144,95 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { | ... | @@ -7144,81 +7144,95 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 7144 | const aliased_reg = registerAlias(abi.getCAbiIntReturnRegs(self.target.*)[0], ret_ty_size); | 7144 | const aliased_reg = registerAlias(abi.getCAbiIntReturnRegs(self.target.*)[0], ret_ty_size); |
| 7145 | result.return_value = .{ .register = aliased_reg }; | 7145 | result.return_value = .{ .register = aliased_reg }; |
| 7146 | } else { | 7146 | } else { |
| 7147 | // We simply make the return MCValue a stack offset. However, the actual value | 7147 | // TODO: return argument cell should go first |
| 7148 | // for the offset will be populated later. We will also push the stack offset | | |
| 7149 | // value into .rdi register when we resolve the offset. | | |
| 7150 | result.return_value = .{ .stack_offset = 0 }; | 7148 | result.return_value = .{ .stack_offset = 0 }; |
| 7151 | } | 7149 | } |
| 7152 | } | 7150 | } |
| 7153 | | 7151 | |
| 7154 | // Input params | 7152 | // Input params |
| 7155 | // First, split into args that can be passed via registers. | 7153 | var next_stack_offset: u32 = switch (result.return_value) { |
| 7156 | // This will make it easier to then push the rest of args in reverse | 7154 | .stack_offset => |off| @intCast(u32, off), |
| 7157 | // order on the stack. | 7155 | else => 0, |
| 7158 | var next_int_reg: usize = 0; | | |
| 7159 | var by_reg = std.AutoHashMap(usize, usize).init(self.bin_file.allocator); | | |
| 7160 | defer by_reg.deinit(); | | |
| 7161 | | | |
| 7162 | // If we want debug output, we store all args on stack for better liveness of args | | |
| 7163 | // in debugging contexts such as previewing the args in the debugger anywhere in | | |
| 7164 | // the procedure. Passing the args via registers can lead to reusing the register | | |
| 7165 | // for local ops thus clobbering the input arg forever. | | |
| 7166 | // This of course excludes C ABI calls. | | |
| 7167 | const omit_args_in_registers = blk: { | | |
| 7168 | if (cc == .C) break :blk false; | | |
| 7169 | switch (self.bin_file.options.optimize_mode) { | | |
| 7170 | .Debug => break :blk true, | | |
| 7171 | else => break :blk false, | | |
| 7172 | } | | |
| 7173 | }; | 7156 | }; |
| 7174 | if (!omit_args_in_registers) { | 7157 | |
| 7175 | for (param_types) |ty, i| { | 7158 | for (param_types) |ty, i| { |
| 7176 | if (!ty.hasRuntimeBits()) continue; | 7159 | assert(ty.hasRuntimeBits()); |
| 7177 | const param_size = @intCast(u32, ty.abiSize(self.target.*)); | 7160 | |
| 7178 | // For simplicity of codegen, slices and other types are always pushed onto the stack. | 7161 | if (self.target.os.tag != .windows) { |
| 7179 | // TODO: look into optimizing this by passing things as registers sometimes, | 7162 | return self.fail("TODO SysV calling convention", .{}); |
| 7180 | // such as ptr and len of slices as separate registers. | 7163 | } |
| 7181 | // TODO: also we need to honor the C ABI for relevant types rather than passing on | 7164 | |
| 7182 | // the stack here. | 7165 | switch (abi.classifyWindows(ty, self.target.*)) { |
| 7183 | const pass_in_reg = switch (ty.zigTypeTag()) { | 7166 | .integer => blk: { |
| 7184 | .Bool => true, | 7167 | if (i >= abi.getCAbiIntParamRegs(self.target.*).len) break :blk; // fallthrough |
| 7185 | .Int, .Enum => param_size <= 8, | 7168 | result.args[i] = .{ .register = abi.getCAbiIntParamRegs(self.target.*)[i] }; |
| 7186 | .Pointer => ty.ptrSize() != .Slice, | 7169 | continue; |
| 7187 | .Optional => ty.isPtrLikeOptional(), | 7170 | }, |
| 7188 | else => false, | 7171 | .sse => return self.fail("TODO float/vector via SSE on Windows", .{}), |
| 7189 | }; | 7172 | .memory => {}, // fallthrough |
| 7190 | if (pass_in_reg) { | 7173 | else => unreachable, |
| 7191 | if (next_int_reg >= abi.getCAbiIntParamRegs(self.target.*).len) break; | 7174 | } |
| 7192 | try by_reg.putNoClobber(i, next_int_reg); | 7175 | |
| 7193 | next_int_reg += 1; | 7176 | const param_size = @intCast(u32, ty.abiSize(self.target.*)); |
| 7194 | } | 7177 | const param_align = @intCast(u32, ty.abiAlignment(self.target.*)); |
| | 7178 | const offset = mem.alignForwardGeneric(u32, next_stack_offset + param_size, param_align); |
| | 7179 | result.args[i] = .{ .stack_offset = @intCast(i32, offset) }; |
| | 7180 | next_stack_offset = offset; |
| | 7181 | } |
| | 7182 | // Align the stack to 16bytes before allocating shadow stack space. |
| | 7183 | const aligned_next_stack_offset = mem.alignForwardGeneric(u32, next_stack_offset, 16); |
| | 7184 | const padding = aligned_next_stack_offset - next_stack_offset; |
| | 7185 | if (padding > 0) { |
| | 7186 | for (result.args) |*arg| { |
| | 7187 | if (arg.isRegister()) continue; |
| | 7188 | arg.stack_offset += @intCast(i32, padding); |
| | 7189 | } |
| | 7190 | } |
| | 7191 | |
| | 7192 | // TODO fix this so that the 16byte alignment padding is at the current value of $rsp, and push |
| | 7193 | // the args onto the stack so that there is no padding between the first argument and |
| | 7194 | // the standard preamble. |
| | 7195 | // alignment padding | ret value (if > 8) | args ... | shadow stack space | $rbp | |
| | 7196 | result.stack_byte_count = aligned_next_stack_offset + 4 * @sizeOf(u64); |
| | 7197 | result.stack_align = 16; |
| | 7198 | }, |
| | 7199 | .Unspecified => { |
| | 7200 | // Return values |
| | 7201 | if (ret_ty.zigTypeTag() == .NoReturn) { |
| | 7202 | result.return_value = .{ .unreach = {} }; |
| | 7203 | } else if (!ret_ty.hasRuntimeBitsIgnoreComptime() and !ret_ty.isError()) { |
| | 7204 | result.return_value = .{ .none = {} }; |
| | 7205 | } else { |
| | 7206 | const ret_ty_size = @intCast(u32, ret_ty.abiSize(self.target.*)); |
| | 7207 | if (ret_ty_size == 0) { |
| | 7208 | assert(ret_ty.isError()); |
| | 7209 | result.return_value = .{ .immediate = 0 }; |
| | 7210 | } else if (ret_ty_size <= 8) { |
| | 7211 | result.return_value = .{ .register = .rdi }; |
| | 7212 | } else { |
| | 7213 | // We simply make the return MCValue a stack offset. However, the actual value |
| | 7214 | // for the offset will be populated later. We will also push the stack offset |
| | 7215 | // value into .rdi register when we resolve the offset. |
| | 7216 | result.return_value = .{ .stack_offset = 0 }; |
| 7195 | } | 7217 | } |
| 7196 | } | 7218 | } |
| 7197 | | 7219 | |
| | 7220 | // Input params |
| 7198 | var next_stack_offset: u32 = switch (result.return_value) { | 7221 | var next_stack_offset: u32 = switch (result.return_value) { |
| 7199 | .stack_offset => |off| @intCast(u32, off), | 7222 | .stack_offset => |off| @intCast(u32, off), |
| 7200 | else => 0, | 7223 | else => 0, |
| 7201 | }; | 7224 | }; |
| 7202 | var count: usize = param_types.len; | 7225 | |
| 7203 | while (count > 0) : (count -= 1) { | 7226 | for (param_types) |ty, i| { |
| 7204 | const i = count - 1; | | |
| 7205 | const ty = param_types[i]; | | |
| 7206 | if (!ty.hasRuntimeBits()) { | 7227 | if (!ty.hasRuntimeBits()) { |
| 7207 | assert(cc != .C); | | |
| 7208 | result.args[i] = .{ .none = {} }; | 7228 | result.args[i] = .{ .none = {} }; |
| 7209 | continue; | 7229 | continue; |
| 7210 | } | 7230 | } |
| 7211 | const param_size = @intCast(u32, ty.abiSize(self.target.*)); | 7231 | const param_size = @intCast(u32, ty.abiSize(self.target.*)); |
| 7212 | const param_align = @intCast(u32, ty.abiAlignment(self.target.*)); | 7232 | const param_align = @intCast(u32, ty.abiAlignment(self.target.*)); |
| 7213 | if (by_reg.get(i)) |int_reg| { | 7233 | const offset = mem.alignForwardGeneric(u32, next_stack_offset + param_size, param_align); |
| 7214 | const aliased_reg = registerAlias(abi.getCAbiIntParamRegs(self.target.*)[int_reg], param_size); | 7234 | result.args[i] = .{ .stack_offset = @intCast(i32, offset) }; |
| 7215 | result.args[i] = .{ .register = aliased_reg }; | 7235 | next_stack_offset = offset; |
| 7216 | next_int_reg += 1; | | |
| 7217 | } else { | | |
| 7218 | const offset = mem.alignForwardGeneric(u32, next_stack_offset + param_size, param_align); | | |
| 7219 | result.args[i] = .{ .stack_offset = @intCast(i32, offset) }; | | |
| 7220 | next_stack_offset = offset; | | |
| 7221 | } | | |
| 7222 | } | 7236 | } |
| 7223 | | 7237 | |
| 7224 | result.stack_align = 16; | 7238 | result.stack_align = 16; |