| ... | ... | @@ -363,17 +363,114 @@ pub fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 { |
| 363 | 363 | } |
| 364 | 364 | |
| 365 | 365 | fn gen(self: *Self) !void { |
| 366 | | _ = try self.addInst(.{ |
| 367 | | .tag = .dbg_prologue_end, |
| 368 | | .data = .{ .nop = {} }, |
| 369 | | }); |
| 366 | const cc = self.fn_type.fnCallingConvention(); |
| 367 | if (cc != .Naked) { |
| 368 | // TODO Finish function prologue and epilogue for riscv64. |
| 369 | |
| 370 | // TODO Backpatch stack offset |
| 371 | // addi sp, sp, -16 |
| 372 | _ = try self.addInst(.{ |
| 373 | .tag = .addi, |
| 374 | .data = .{ .i_type = .{ |
| 375 | .rd = .sp, |
| 376 | .rs1 = .sp, |
| 377 | .imm12 = -16, |
| 378 | } }, |
| 379 | }); |
| 370 | 380 | |
| 371 | | try self.genBody(self.air.getMainBody()); |
| 381 | // sd ra, 8(sp) |
| 382 | _ = try self.addInst(.{ |
| 383 | .tag = .sd, |
| 384 | .data = .{ .i_type = .{ |
| 385 | .rd = .ra, |
| 386 | .rs1 = .sp, |
| 387 | .imm12 = 8, |
| 388 | } }, |
| 389 | }); |
| 372 | 390 | |
| 373 | | _ = try self.addInst(.{ |
| 374 | | .tag = .dbg_epilogue_begin, |
| 375 | | .data = .{ .nop = {} }, |
| 376 | | }); |
| 391 | // sd s0, 0(sp) |
| 392 | _ = try self.addInst(.{ |
| 393 | .tag = .sd, |
| 394 | .data = .{ .i_type = .{ |
| 395 | .rd = .s0, |
| 396 | .rs1 = .sp, |
| 397 | .imm12 = 0, |
| 398 | } }, |
| 399 | }); |
| 400 | |
| 401 | _ = try self.addInst(.{ |
| 402 | .tag = .dbg_prologue_end, |
| 403 | .data = .{ .nop = {} }, |
| 404 | }); |
| 405 | |
| 406 | try self.genBody(self.air.getMainBody()); |
| 407 | |
| 408 | _ = try self.addInst(.{ |
| 409 | .tag = .dbg_epilogue_begin, |
| 410 | .data = .{ .nop = {} }, |
| 411 | }); |
| 412 | |
| 413 | // exitlude jumps |
| 414 | if (self.exitlude_jump_relocs.items.len == 1) { |
| 415 | // There is only one relocation. Hence, |
| 416 | // this relocation must be at the end of |
| 417 | // the code. Therefore, we can just delete |
| 418 | // the space initially reserved for the |
| 419 | // jump |
| 420 | self.mir_instructions.len -= 1; |
| 421 | } else for (self.exitlude_jump_relocs.items) |jmp_reloc| { |
| 422 | _ = jmp_reloc; |
| 423 | return self.fail("TODO add branches in RISCV64", .{}); |
| 424 | } |
| 425 | |
| 426 | // ld ra, 8(sp) |
| 427 | _ = try self.addInst(.{ |
| 428 | .tag = .ld, |
| 429 | .data = .{ .i_type = .{ |
| 430 | .rd = .ra, |
| 431 | .rs1 = .sp, |
| 432 | .imm12 = 8, |
| 433 | } }, |
| 434 | }); |
| 435 | |
| 436 | // ld s0, 0(sp) |
| 437 | _ = try self.addInst(.{ |
| 438 | .tag = .ld, |
| 439 | .data = .{ .i_type = .{ |
| 440 | .rd = .s0, |
| 441 | .rs1 = .sp, |
| 442 | .imm12 = 0, |
| 443 | } }, |
| 444 | }); |
| 445 | |
| 446 | // addi sp, sp, 16 |
| 447 | _ = try self.addInst(.{ |
| 448 | .tag = .addi, |
| 449 | .data = .{ .i_type = .{ |
| 450 | .rd = .sp, |
| 451 | .rs1 = .sp, |
| 452 | .imm12 = 16, |
| 453 | } }, |
| 454 | }); |
| 455 | |
| 456 | // ret |
| 457 | _ = try self.addInst(.{ |
| 458 | .tag = .ret, |
| 459 | .data = .{ .nop = {} }, |
| 460 | }); |
| 461 | } else { |
| 462 | _ = try self.addInst(.{ |
| 463 | .tag = .dbg_prologue_end, |
| 464 | .data = .{ .nop = {} }, |
| 465 | }); |
| 466 | |
| 467 | try self.genBody(self.air.getMainBody()); |
| 468 | |
| 469 | _ = try self.addInst(.{ |
| 470 | .tag = .dbg_epilogue_begin, |
| 471 | .data = .{ .nop = {} }, |
| 472 | }); |
| 473 | } |
| 377 | 474 | |
| 378 | 475 | // Drop them off at the rbrace. |
| 379 | 476 | _ = try self.addInst(.{ |
| ... | ... | @@ -1317,7 +1414,36 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { |
| 1317 | 1414 | // Due to incremental compilation, how function calls are generated depends |
| 1318 | 1415 | // on linking. |
| 1319 | 1416 | if (self.bin_file.tag == link.File.Elf.base_tag or self.bin_file.tag == link.File.Coff.base_tag) { |
| 1320 | | if (info.args.len > 0) return self.fail("TODO implement fn args for {}", .{self.target.cpu.arch}); |
| 1417 | for (info.args) |mc_arg, arg_i| { |
| 1418 | const arg = args[arg_i]; |
| 1419 | const arg_ty = self.air.typeOf(arg); |
| 1420 | const arg_mcv = try self.resolveInst(args[arg_i]); |
| 1421 | |
| 1422 | switch (mc_arg) { |
| 1423 | .none => continue, |
| 1424 | .undef => unreachable, |
| 1425 | .immediate => unreachable, |
| 1426 | .unreach => unreachable, |
| 1427 | .dead => unreachable, |
| 1428 | .embedded_in_code => unreachable, |
| 1429 | .memory => unreachable, |
| 1430 | .compare_flags_signed => unreachable, |
| 1431 | .compare_flags_unsigned => unreachable, |
| 1432 | .register => |reg| { |
| 1433 | try self.register_manager.getReg(reg, null); |
| 1434 | try self.genSetReg(arg_ty, reg, arg_mcv); |
| 1435 | }, |
| 1436 | .stack_offset => { |
| 1437 | return self.fail("TODO implement calling with parameters in memory", .{}); |
| 1438 | }, |
| 1439 | .ptr_stack_offset => { |
| 1440 | return self.fail("TODO implement calling with MCValue.ptr_stack_offset arg", .{}); |
| 1441 | }, |
| 1442 | .ptr_embedded_in_code => { |
| 1443 | return self.fail("TODO implement calling with MCValue.ptr_embedded_in_code arg", .{}); |
| 1444 | }, |
| 1445 | } |
| 1446 | } |
| 1321 | 1447 | |
| 1322 | 1448 | if (self.air.value(callee)) |func_value| { |
| 1323 | 1449 | if (func_value.castTag(.function)) |func_payload| { |
| ... | ... | @@ -1386,14 +1512,12 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { |
| 1386 | 1512 | fn ret(self: *Self, mcv: MCValue) !void { |
| 1387 | 1513 | const ret_ty = self.fn_type.fnReturnType(); |
| 1388 | 1514 | try self.setRegOrMem(ret_ty, self.ret_mcv, mcv); |
| 1389 | | _ = try self.addInst(.{ |
| 1390 | | .tag = .jalr, |
| 1391 | | .data = .{ .i_type = .{ |
| 1392 | | .rd = .zero, |
| 1393 | | .rs1 = .ra, |
| 1394 | | .imm12 = 0, |
| 1395 | | } }, |
| 1515 | // Just add space for an instruction, patch this later |
| 1516 | const index = try self.addInst(.{ |
| 1517 | .tag = .nop, |
| 1518 | .data = .{ .nop = {} }, |
| 1396 | 1519 | }); |
| 1520 | try self.exitlude_jump_relocs.append(self.gpa, index); |
| 1397 | 1521 | } |
| 1398 | 1522 | |
| 1399 | 1523 | fn airRet(self: *Self, inst: Air.Inst.Index) !void { |
| ... | ... | @@ -2156,7 +2280,6 @@ const CallMCValues = struct { |
| 2156 | 2280 | /// Caller must call `CallMCValues.deinit`. |
| 2157 | 2281 | fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 2158 | 2282 | const cc = fn_ty.fnCallingConvention(); |
| 2159 | | _ = cc; |
| 2160 | 2283 | const param_types = try self.gpa.alloc(Type, fn_ty.fnParamLen()); |
| 2161 | 2284 | defer self.gpa.free(param_types); |
| 2162 | 2285 | fn_ty.fnParamTypes(param_types); |
| ... | ... | @@ -2171,15 +2294,73 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 2171 | 2294 | |
| 2172 | 2295 | const ret_ty = fn_ty.fnReturnType(); |
| 2173 | 2296 | |
| 2174 | | if (param_types.len != 0) { |
| 2175 | | return self.fail("TODO implement codegen parameters for {}", .{self.target.cpu.arch}); |
| 2297 | switch (cc) { |
| 2298 | .Naked => { |
| 2299 | assert(result.args.len == 0); |
| 2300 | result.return_value = .{ .unreach = {} }; |
| 2301 | result.stack_byte_count = 0; |
| 2302 | result.stack_align = 1; |
| 2303 | return result; |
| 2304 | }, |
| 2305 | .Unspecified, .C => { |
| 2306 | // LP64D ABI |
| 2307 | // |
| 2308 | // TODO make this generic with other ABIs, in particular |
| 2309 | // with different hardware floating-point calling |
| 2310 | // conventions |
| 2311 | var next_register: usize = 0; |
| 2312 | var next_stack_offset: u32 = 0; |
| 2313 | const argument_registers = [_]Register{ .a0, .a1, .a2, .a3, .a4, .a5, .a6, .a7 }; |
| 2314 | |
| 2315 | for (param_types) |ty, i| { |
| 2316 | const param_size = @intCast(u32, ty.abiSize(self.target.*)); |
| 2317 | if (param_size <= 8) { |
| 2318 | if (next_register < argument_registers.len) { |
| 2319 | result.args[i] = .{ .register = argument_registers[next_register] }; |
| 2320 | next_register += 1; |
| 2321 | } else { |
| 2322 | result.args[i] = .{ .stack_offset = next_stack_offset }; |
| 2323 | next_register += next_stack_offset; |
| 2324 | } |
| 2325 | } else if (param_size <= 16) { |
| 2326 | if (next_register < argument_registers.len - 1) { |
| 2327 | return self.fail("TODO MCValues with 2 registers", .{}); |
| 2328 | } else if (next_register < argument_registers.len) { |
| 2329 | return self.fail("TODO MCValues split register + stack", .{}); |
| 2330 | } else { |
| 2331 | result.args[i] = .{ .stack_offset = next_stack_offset }; |
| 2332 | next_register += next_stack_offset; |
| 2333 | } |
| 2334 | } else { |
| 2335 | result.args[i] = .{ .stack_offset = next_stack_offset }; |
| 2336 | next_register += next_stack_offset; |
| 2337 | } |
| 2338 | } |
| 2339 | |
| 2340 | result.stack_byte_count = next_stack_offset; |
| 2341 | result.stack_align = 16; |
| 2342 | }, |
| 2343 | else => return self.fail("TODO implement function parameters for {} on aarch64", .{cc}), |
| 2176 | 2344 | } |
| 2177 | 2345 | |
| 2178 | 2346 | if (ret_ty.zigTypeTag() == .NoReturn) { |
| 2179 | 2347 | result.return_value = .{ .unreach = {} }; |
| 2180 | 2348 | } else if (!ret_ty.hasCodeGenBits()) { |
| 2181 | 2349 | result.return_value = .{ .none = {} }; |
| 2182 | | } else return self.fail("TODO implement codegen return values for {}", .{self.target.cpu.arch}); |
| 2350 | } else switch (cc) { |
| 2351 | .Naked => unreachable, |
| 2352 | .Unspecified, .C => { |
| 2353 | const ret_ty_size = @intCast(u32, ret_ty.abiSize(self.target.*)); |
| 2354 | if (ret_ty_size <= 8) { |
| 2355 | result.return_value = .{ .register = .a0 }; |
| 2356 | } else if (ret_ty_size <= 16) { |
| 2357 | return self.fail("TODO support MCValue 2 registers", .{}); |
| 2358 | } else { |
| 2359 | return self.fail("TODO support return by reference", .{}); |
| 2360 | } |
| 2361 | }, |
| 2362 | else => return self.fail("TODO implement function return values for {}", .{cc}), |
| 2363 | } |
| 2183 | 2364 | return result; |
| 2184 | 2365 | } |
| 2185 | 2366 | |