| ... | @@ -2073,41 +2073,41 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2073,41 +2073,41 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { |
| 2073 | var info = try self.resolveCallingConventionValues(fn_ty); | 2073 | var info = try self.resolveCallingConventionValues(fn_ty); |
| 2074 | defer info.deinit(self); | 2074 | defer info.deinit(self); |
| 2075 | | 2075 | |
| 2076 | // Due to incremental compilation, how function calls are generated depends | 2076 | for (info.args) |mc_arg, arg_i| { |
| 2077 | // on linking. | 2077 | const arg = args[arg_i]; |
| 2078 | if (self.bin_file.tag == link.File.Elf.base_tag or self.bin_file.tag == link.File.Coff.base_tag) { | 2078 | const arg_ty = self.air.typeOf(arg); |
| 2079 | for (info.args) |mc_arg, arg_i| { | 2079 | const arg_mcv = try self.resolveInst(args[arg_i]); |
| 2080 | const arg = args[arg_i]; | 2080 | |
| 2081 | const arg_ty = self.air.typeOf(arg); | 2081 | switch (mc_arg) { |
| 2082 | const arg_mcv = try self.resolveInst(args[arg_i]); | 2082 | .none => continue, |
| 2083 | | 2083 | .undef => unreachable, |
| 2084 | switch (mc_arg) { | 2084 | .immediate => unreachable, |
| 2085 | .none => continue, | 2085 | .unreach => unreachable, |
| 2086 | .undef => unreachable, | 2086 | .dead => unreachable, |
| 2087 | .immediate => unreachable, | 2087 | .embedded_in_code => unreachable, |
| 2088 | .unreach => unreachable, | 2088 | .memory => unreachable, |
| 2089 | .dead => unreachable, | 2089 | .compare_flags_signed => unreachable, |
| 2090 | .embedded_in_code => unreachable, | 2090 | .compare_flags_unsigned => unreachable, |
| 2091 | .memory => unreachable, | 2091 | .register => |reg| { |
| 2092 | .compare_flags_signed => unreachable, | 2092 | try self.register_manager.getReg(reg, null); |
| 2093 | .compare_flags_unsigned => unreachable, | 2093 | try self.genSetReg(arg_ty, reg, arg_mcv); |
| 2094 | .register => |reg| { | 2094 | }, |
| 2095 | try self.register_manager.getReg(reg, null); | 2095 | .stack_offset => { |
| 2096 | try self.genSetReg(arg_ty, reg, arg_mcv); | 2096 | return self.fail("TODO implement calling with parameters in memory", .{}); |
| 2097 | }, | 2097 | }, |
| 2098 | .stack_offset => { | 2098 | .ptr_stack_offset => { |
| 2099 | return self.fail("TODO implement calling with parameters in memory", .{}); | 2099 | return self.fail("TODO implement calling with MCValue.ptr_stack_offset arg", .{}); |
| 2100 | }, | 2100 | }, |
| 2101 | .ptr_stack_offset => { | 2101 | .ptr_embedded_in_code => { |
| 2102 | return self.fail("TODO implement calling with MCValue.ptr_stack_offset arg", .{}); | 2102 | return self.fail("TODO implement calling with MCValue.ptr_embedded_in_code arg", .{}); |
| 2103 | }, | 2103 | }, |
| 2104 | .ptr_embedded_in_code => { | | |
| 2105 | return self.fail("TODO implement calling with MCValue.ptr_embedded_in_code arg", .{}); | | |
| 2106 | }, | | |
| 2107 | } | | |
| 2108 | } | 2104 | } |
| | 2105 | } |
| 2109 | | 2106 | |
| 2110 | if (self.air.value(callee)) |func_value| { | 2107 | // Due to incremental compilation, how function calls are generated depends |
| | 2108 | // on linking. |
| | 2109 | if (self.air.value(callee)) |func_value| { |
| | 2110 | if (self.bin_file.tag == link.File.Elf.base_tag or self.bin_file.tag == link.File.Coff.base_tag) { |
| 2111 | if (func_value.castTag(.function)) |func_payload| { | 2111 | if (func_value.castTag(.function)) |func_payload| { |
| 2112 | const func = func_payload.data; | 2112 | const func = func_payload.data; |
| 2113 | const ptr_bits = self.target.cpu.arch.ptrBitWidth(); | 2113 | const ptr_bits = self.target.cpu.arch.ptrBitWidth(); |
| ... | @@ -2131,52 +2131,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2131,52 +2131,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { |
| 2131 | } else { | 2131 | } else { |
| 2132 | return self.fail("TODO implement calling bitcasted functions", .{}); | 2132 | return self.fail("TODO implement calling bitcasted functions", .{}); |
| 2133 | } | 2133 | } |
| 2134 | } else { | 2134 | } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { |
| 2135 | assert(ty.zigTypeTag() == .Pointer); | | |
| 2136 | const mcv = try self.resolveInst(callee); | | |
| 2137 | try self.genSetReg(Type.initTag(.usize), .x30, mcv); | | |
| 2138 | | | |
| 2139 | _ = try self.addInst(.{ | | |
| 2140 | .tag = .blr, | | |
| 2141 | .data = .{ .reg = .x30 }, | | |
| 2142 | }); | | |
| 2143 | } | | |
| 2144 | } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { | | |
| 2145 | for (info.args) |mc_arg, arg_i| { | | |
| 2146 | const arg = args[arg_i]; | | |
| 2147 | const arg_ty = self.air.typeOf(arg); | | |
| 2148 | const arg_mcv = try self.resolveInst(args[arg_i]); | | |
| 2149 | // Here we do not use setRegOrMem even though the logic is similar, because | | |
| 2150 | // the function call will move the stack pointer, so the offsets are different. | | |
| 2151 | switch (mc_arg) { | | |
| 2152 | .none => continue, | | |
| 2153 | .register => |reg| { | | |
| 2154 | try self.register_manager.getReg(reg, null); | | |
| 2155 | try self.genSetReg(arg_ty, reg, arg_mcv); | | |
| 2156 | }, | | |
| 2157 | .stack_offset => { | | |
| 2158 | // Here we need to emit instructions like this: | | |
| 2159 | // mov qword ptr [rsp + stack_offset], x | | |
| 2160 | return self.fail("TODO implement calling with parameters in memory", .{}); | | |
| 2161 | }, | | |
| 2162 | .ptr_stack_offset => { | | |
| 2163 | return self.fail("TODO implement calling with MCValue.ptr_stack_offset arg", .{}); | | |
| 2164 | }, | | |
| 2165 | .ptr_embedded_in_code => { | | |
| 2166 | return self.fail("TODO implement calling with MCValue.ptr_embedded_in_code arg", .{}); | | |
| 2167 | }, | | |
| 2168 | .undef => unreachable, | | |
| 2169 | .immediate => unreachable, | | |
| 2170 | .unreach => unreachable, | | |
| 2171 | .dead => unreachable, | | |
| 2172 | .embedded_in_code => unreachable, | | |
| 2173 | .memory => unreachable, | | |
| 2174 | .compare_flags_signed => unreachable, | | |
| 2175 | .compare_flags_unsigned => unreachable, | | |
| 2176 | } | | |
| 2177 | } | | |
| 2178 | | | |
| 2179 | if (self.air.value(callee)) |func_value| { | | |
| 2180 | if (func_value.castTag(.function)) |func_payload| { | 2135 | if (func_value.castTag(.function)) |func_payload| { |
| 2181 | const func = func_payload.data; | 2136 | const func = func_payload.data; |
| 2182 | // TODO I'm hacking my way through here by repurposing .memory for storing | 2137 | // TODO I'm hacking my way through here by repurposing .memory for storing |
| ... | @@ -2212,41 +2167,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2212,41 +2167,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { |
| 2212 | } else { | 2167 | } else { |
| 2213 | return self.fail("TODO implement calling bitcasted functions", .{}); | 2168 | return self.fail("TODO implement calling bitcasted functions", .{}); |
| 2214 | } | 2169 | } |
| 2215 | } else { | 2170 | } else if (self.bin_file.cast(link.File.Plan9)) |p9| { |
| 2216 | return self.fail("TODO implement calling runtime known function pointer", .{}); | | |
| 2217 | } | | |
| 2218 | } else if (self.bin_file.cast(link.File.Plan9)) |p9| { | | |
| 2219 | for (info.args) |mc_arg, arg_i| { | | |
| 2220 | const arg = args[arg_i]; | | |
| 2221 | const arg_ty = self.air.typeOf(arg); | | |
| 2222 | const arg_mcv = try self.resolveInst(args[arg_i]); | | |
| 2223 | | | |
| 2224 | switch (mc_arg) { | | |
| 2225 | .none => continue, | | |
| 2226 | .undef => unreachable, | | |
| 2227 | .immediate => unreachable, | | |
| 2228 | .unreach => unreachable, | | |
| 2229 | .dead => unreachable, | | |
| 2230 | .embedded_in_code => unreachable, | | |
| 2231 | .memory => unreachable, | | |
| 2232 | .compare_flags_signed => unreachable, | | |
| 2233 | .compare_flags_unsigned => unreachable, | | |
| 2234 | .register => |reg| { | | |
| 2235 | try self.register_manager.getReg(reg, null); | | |
| 2236 | try self.genSetReg(arg_ty, reg, arg_mcv); | | |
| 2237 | }, | | |
| 2238 | .stack_offset => { | | |
| 2239 | return self.fail("TODO implement calling with parameters in memory", .{}); | | |
| 2240 | }, | | |
| 2241 | .ptr_stack_offset => { | | |
| 2242 | return self.fail("TODO implement calling with MCValue.ptr_stack_offset arg", .{}); | | |
| 2243 | }, | | |
| 2244 | .ptr_embedded_in_code => { | | |
| 2245 | return self.fail("TODO implement calling with MCValue.ptr_embedded_in_code arg", .{}); | | |
| 2246 | }, | | |
| 2247 | } | | |
| 2248 | } | | |
| 2249 | if (self.air.value(callee)) |func_value| { | | |
| 2250 | if (func_value.castTag(.function)) |func_payload| { | 2171 | if (func_value.castTag(.function)) |func_payload| { |
| 2251 | try p9.seeDecl(func_payload.data.owner_decl); | 2172 | try p9.seeDecl(func_payload.data.owner_decl); |
| 2252 | const ptr_bits = self.target.cpu.arch.ptrBitWidth(); | 2173 | const ptr_bits = self.target.cpu.arch.ptrBitWidth(); |
| ... | @@ -2266,10 +2187,17 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2266,10 +2187,17 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { |
| 2266 | } else { | 2187 | } else { |
| 2267 | return self.fail("TODO implement calling bitcasted functions", .{}); | 2188 | return self.fail("TODO implement calling bitcasted functions", .{}); |
| 2268 | } | 2189 | } |
| 2269 | } else { | 2190 | } else unreachable; |
| 2270 | return self.fail("TODO implement calling runtime known function pointer", .{}); | 2191 | } else { |
| 2271 | } | 2192 | assert(ty.zigTypeTag() == .Pointer); |
| 2272 | } else unreachable; | 2193 | const mcv = try self.resolveInst(callee); |
| | 2194 | try self.genSetReg(ty, .x30, mcv); |
| | 2195 | |
| | 2196 | _ = try self.addInst(.{ |
| | 2197 | .tag = .blr, |
| | 2198 | .data = .{ .reg = .x30 }, |
| | 2199 | }); |
| | 2200 | } |
| 2273 | | 2201 | |
| 2274 | const result: MCValue = result: { | 2202 | const result: MCValue = result: { |
| 2275 | switch (info.return_value) { | 2203 | switch (info.return_value) { |