| ... | @@ -363,17 +363,114 @@ pub fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 { | ... | @@ -363,17 +363,114 @@ pub fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 { |
| 363 | } | 363 | } |
| 364 | | 364 | |
| 365 | fn gen(self: *Self) !void { | 365 | fn gen(self: *Self) !void { |
| 366 | _ = try self.addInst(.{ | 366 | const cc = self.fn_type.fnCallingConvention(); |
| 367 | .tag = .dbg_prologue_end, | 367 | if (cc != .Naked) { |
| 368 | .data = .{ .nop = {} }, | 368 | // TODO Finish function prologue and epilogue for riscv64. |
| 369 | }); | 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(.{ | 391 | // sd s0, 0(sp) |
| 374 | .tag = .dbg_epilogue_begin, | 392 | _ = try self.addInst(.{ |
| 375 | .data = .{ .nop = {} }, | 393 | .tag = .sd, |
| 376 | }); | 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 | // Drop them off at the rbrace. | 475 | // Drop them off at the rbrace. |
| 379 | _ = try self.addInst(.{ | 476 | _ = try self.addInst(.{ |
| ... | @@ -1317,7 +1414,36 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1317,7 +1414,36 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { |
| 1317 | // Due to incremental compilation, how function calls are generated depends | 1414 | // Due to incremental compilation, how function calls are generated depends |
| 1318 | // on linking. | 1415 | // on linking. |
| 1319 | if (self.bin_file.tag == link.File.Elf.base_tag or self.bin_file.tag == link.File.Coff.base_tag) { | 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 | if (self.air.value(callee)) |func_value| { | 1448 | if (self.air.value(callee)) |func_value| { |
| 1323 | if (func_value.castTag(.function)) |func_payload| { | 1449 | if (func_value.castTag(.function)) |func_payload| { |
| ... | @@ -1386,14 +1512,12 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1386,14 +1512,12 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { |
| 1386 | fn ret(self: *Self, mcv: MCValue) !void { | 1512 | fn ret(self: *Self, mcv: MCValue) !void { |
| 1387 | const ret_ty = self.fn_type.fnReturnType(); | 1513 | const ret_ty = self.fn_type.fnReturnType(); |
| 1388 | try self.setRegOrMem(ret_ty, self.ret_mcv, mcv); | 1514 | try self.setRegOrMem(ret_ty, self.ret_mcv, mcv); |
| 1389 | _ = try self.addInst(.{ | 1515 | // Just add space for an instruction, patch this later |
| 1390 | .tag = .jalr, | 1516 | const index = try self.addInst(.{ |
| 1391 | .data = .{ .i_type = .{ | 1517 | .tag = .nop, |
| 1392 | .rd = .zero, | 1518 | .data = .{ .nop = {} }, |
| 1393 | .rs1 = .ra, | | |
| 1394 | .imm12 = 0, | | |
| 1395 | } }, | | |
| 1396 | }); | 1519 | }); |
| | 1520 | try self.exitlude_jump_relocs.append(self.gpa, index); |
| 1397 | } | 1521 | } |
| 1398 | | 1522 | |
| 1399 | fn airRet(self: *Self, inst: Air.Inst.Index) !void { | 1523 | fn airRet(self: *Self, inst: Air.Inst.Index) !void { |
| ... | @@ -2156,7 +2280,6 @@ const CallMCValues = struct { | ... | @@ -2156,7 +2280,6 @@ const CallMCValues = struct { |
| 2156 | /// Caller must call `CallMCValues.deinit`. | 2280 | /// Caller must call `CallMCValues.deinit`. |
| 2157 | fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { | 2281 | fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 2158 | const cc = fn_ty.fnCallingConvention(); | 2282 | const cc = fn_ty.fnCallingConvention(); |
| 2159 | _ = cc; | | |
| 2160 | const param_types = try self.gpa.alloc(Type, fn_ty.fnParamLen()); | 2283 | const param_types = try self.gpa.alloc(Type, fn_ty.fnParamLen()); |
| 2161 | defer self.gpa.free(param_types); | 2284 | defer self.gpa.free(param_types); |
| 2162 | fn_ty.fnParamTypes(param_types); | 2285 | fn_ty.fnParamTypes(param_types); |
| ... | @@ -2171,15 +2294,73 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { | ... | @@ -2171,15 +2294,73 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 2171 | | 2294 | |
| 2172 | const ret_ty = fn_ty.fnReturnType(); | 2295 | const ret_ty = fn_ty.fnReturnType(); |
| 2173 | | 2296 | |
| 2174 | if (param_types.len != 0) { | 2297 | switch (cc) { |
| 2175 | return self.fail("TODO implement codegen parameters for {}", .{self.target.cpu.arch}); | 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 | if (ret_ty.zigTypeTag() == .NoReturn) { | 2346 | if (ret_ty.zigTypeTag() == .NoReturn) { |
| 2179 | result.return_value = .{ .unreach = {} }; | 2347 | result.return_value = .{ .unreach = {} }; |
| 2180 | } else if (!ret_ty.hasCodeGenBits()) { | 2348 | } else if (!ret_ty.hasCodeGenBits()) { |
| 2181 | result.return_value = .{ .none = {} }; | 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 | return result; | 2364 | return result; |
| 2184 | } | 2365 | } |
| 2185 | | 2366 | |