| ... | @@ -33,7 +33,6 @@ const abi = @import("abi.zig"); | ... | @@ -33,7 +33,6 @@ const abi = @import("abi.zig"); |
| 33 | const Register = bits.Register; | 33 | const Register = bits.Register; |
| 34 | const RegisterManager = abi.RegisterManager; | 34 | const RegisterManager = abi.RegisterManager; |
| 35 | const RegisterLock = RegisterManager.RegisterLock; | 35 | const RegisterLock = RegisterManager.RegisterLock; |
| 36 | const Instruction = abi.Instruction; | | |
| 37 | const callee_preserved_regs = abi.callee_preserved_regs; | 36 | const callee_preserved_regs = abi.callee_preserved_regs; |
| 38 | const gp = abi.RegisterClass.gp; | 37 | const gp = abi.RegisterClass.gp; |
| 39 | | 38 | |
| ... | @@ -96,6 +95,8 @@ air_bookkeeping: @TypeOf(air_bookkeeping_init) = air_bookkeeping_init, | ... | @@ -96,6 +95,8 @@ air_bookkeeping: @TypeOf(air_bookkeeping_init) = air_bookkeeping_init, |
| 96 | | 95 | |
| 97 | const air_bookkeeping_init = if (std.debug.runtime_safety) @as(usize, 0) else {}; | 96 | const air_bookkeeping_init = if (std.debug.runtime_safety) @as(usize, 0) else {}; |
| 98 | | 97 | |
| | 98 | const SymbolOffset = struct { sym: u32, off: i32 = 0 }; |
| | 99 | |
| 99 | const MCValue = union(enum) { | 100 | const MCValue = union(enum) { |
| 100 | /// No runtime bits. `void` types, empty structs, u0, enums with 1 tag, etc. | 101 | /// No runtime bits. `void` types, empty structs, u0, enums with 1 tag, etc. |
| 101 | /// TODO Look into deleting this tag and using `dead` instead, since every use | 102 | /// TODO Look into deleting this tag and using `dead` instead, since every use |
| ... | @@ -110,6 +111,9 @@ const MCValue = union(enum) { | ... | @@ -110,6 +111,9 @@ const MCValue = union(enum) { |
| 110 | /// A pointer-sized integer that fits in a register. | 111 | /// A pointer-sized integer that fits in a register. |
| 111 | /// If the type is a pointer, this is the pointer address in virtual address space. | 112 | /// If the type is a pointer, this is the pointer address in virtual address space. |
| 112 | immediate: u64, | 113 | immediate: u64, |
| | 114 | /// The value is in memory at an address not-yet-allocated by the linker. |
| | 115 | /// This traditionally corresponds to a relocation emitted in a relocatable object file. |
| | 116 | load_symbol: SymbolOffset, |
| 113 | /// The value is in a target-specific register. | 117 | /// The value is in a target-specific register. |
| 114 | register: Register, | 118 | register: Register, |
| 115 | /// The value is in memory at a hard-coded address. | 119 | /// The value is in memory at a hard-coded address. |
| ... | @@ -145,6 +149,7 @@ const MCValue = union(enum) { | ... | @@ -145,6 +149,7 @@ const MCValue = union(enum) { |
| 145 | .memory, | 149 | .memory, |
| 146 | .ptr_stack_offset, | 150 | .ptr_stack_offset, |
| 147 | .undef, | 151 | .undef, |
| | 152 | .load_symbol, |
| 148 | => false, | 153 | => false, |
| 149 | | 154 | |
| 150 | .register, | 155 | .register, |
| ... | @@ -165,12 +170,12 @@ const Branch = struct { | ... | @@ -165,12 +170,12 @@ const Branch = struct { |
| 165 | | 170 | |
| 166 | const StackAllocation = struct { | 171 | const StackAllocation = struct { |
| 167 | inst: Air.Inst.Index, | 172 | inst: Air.Inst.Index, |
| 168 | /// TODO do we need size? should be determined by inst.ty.abiSize() | 173 | /// TODO: make the size inferred from the bits of the inst |
| 169 | size: u32, | 174 | size: u32, |
| 170 | }; | 175 | }; |
| 171 | | 176 | |
| 172 | const BlockData = struct { | 177 | const BlockData = struct { |
| 173 | relocs: std.ArrayListUnmanaged(Reloc), | 178 | relocs: std.ArrayListUnmanaged(Mir.Inst.Index), |
| 174 | /// The first break instruction encounters `null` here and chooses a | 179 | /// The first break instruction encounters `null` here and chooses a |
| 175 | /// machine code value for the block result, populating this field. | 180 | /// machine code value for the block result, populating this field. |
| 176 | /// Following break instructions encounter that value and use it for | 181 | /// Following break instructions encounter that value and use it for |
| ... | @@ -178,18 +183,6 @@ const BlockData = struct { | ... | @@ -178,18 +183,6 @@ const BlockData = struct { |
| 178 | mcv: MCValue, | 183 | mcv: MCValue, |
| 179 | }; | 184 | }; |
| 180 | | 185 | |
| 181 | const Reloc = union(enum) { | | |
| 182 | /// The value is an offset into the `Function` `code` from the beginning. | | |
| 183 | /// To perform the reloc, write 32-bit signed little-endian integer | | |
| 184 | /// which is a relative jump, based on the address following the reloc. | | |
| 185 | rel32: usize, | | |
| 186 | /// A branch in the ARM instruction set | | |
| 187 | arm_branch: struct { | | |
| 188 | pos: usize, | | |
| 189 | cond: @import("../arm/bits.zig").Condition, | | |
| 190 | }, | | |
| 191 | }; | | |
| 192 | | | |
| 193 | const BigTomb = struct { | 186 | const BigTomb = struct { |
| 194 | function: *Self, | 187 | function: *Self, |
| 195 | inst: Air.Inst.Index, | 188 | inst: Air.Inst.Index, |
| ... | @@ -272,6 +265,7 @@ pub fn generate( | ... | @@ -272,6 +265,7 @@ pub fn generate( |
| 272 | }, | 265 | }, |
| 273 | else => |e| return e, | 266 | else => |e| return e, |
| 274 | }; | 267 | }; |
| | 268 | |
| 275 | defer call_info.deinit(&function); | 269 | defer call_info.deinit(&function); |
| 276 | | 270 | |
| 277 | function.args = call_info.args; | 271 | function.args = call_info.args; |
| ... | @@ -328,6 +322,13 @@ fn addInst(self: *Self, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index { | ... | @@ -328,6 +322,13 @@ fn addInst(self: *Self, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index { |
| 328 | return result_index; | 322 | return result_index; |
| 329 | } | 323 | } |
| 330 | | 324 | |
| | 325 | fn addNop(self: *Self) error{OutOfMemory}!Mir.Inst.Index { |
| | 326 | return try self.addInst(.{ |
| | 327 | .tag = .nop, |
| | 328 | .data = .{ .nop = {} }, |
| | 329 | }); |
| | 330 | } |
| | 331 | |
| 331 | pub fn addExtra(self: *Self, extra: anytype) Allocator.Error!u32 { | 332 | pub fn addExtra(self: *Self, extra: anytype) Allocator.Error!u32 { |
| 332 | const fields = std.meta.fields(@TypeOf(extra)); | 333 | const fields = std.meta.fields(@TypeOf(extra)); |
| 333 | try self.mir_extra.ensureUnusedCapacity(self.gpa, fields.len); | 334 | try self.mir_extra.ensureUnusedCapacity(self.gpa, fields.len); |
| ... | @@ -350,115 +351,45 @@ pub fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 { | ... | @@ -350,115 +351,45 @@ pub fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 { |
| 350 | fn gen(self: *Self) !void { | 351 | fn gen(self: *Self) !void { |
| 351 | const mod = self.bin_file.comp.module.?; | 352 | const mod = self.bin_file.comp.module.?; |
| 352 | const cc = self.fn_type.fnCallingConvention(mod); | 353 | const cc = self.fn_type.fnCallingConvention(mod); |
| 353 | if (cc != .Naked) { | | |
| 354 | // TODO Finish function prologue and epilogue for riscv64. | | |
| 355 | | | |
| 356 | // TODO Backpatch stack offset | | |
| 357 | // addi sp, sp, -16 | | |
| 358 | _ = try self.addInst(.{ | | |
| 359 | .tag = .addi, | | |
| 360 | .data = .{ .i_type = .{ | | |
| 361 | .rd = .sp, | | |
| 362 | .rs1 = .sp, | | |
| 363 | .imm12 = -16, | | |
| 364 | } }, | | |
| 365 | }); | | |
| 366 | | 354 | |
| 367 | // sd ra, 8(sp) | 355 | if (cc == .Naked) return self.fail("TODO: gen support callconv(.{s})", .{@tagName(cc)}); |
| 368 | _ = try self.addInst(.{ | | |
| 369 | .tag = .sd, | | |
| 370 | .data = .{ .i_type = .{ | | |
| 371 | .rd = .ra, | | |
| 372 | .rs1 = .sp, | | |
| 373 | .imm12 = 8, | | |
| 374 | } }, | | |
| 375 | }); | | |
| 376 | | | |
| 377 | // sd s0, 0(sp) | | |
| 378 | _ = try self.addInst(.{ | | |
| 379 | .tag = .sd, | | |
| 380 | .data = .{ .i_type = .{ | | |
| 381 | .rd = .s0, | | |
| 382 | .rs1 = .sp, | | |
| 383 | .imm12 = 0, | | |
| 384 | } }, | | |
| 385 | }); | | |
| 386 | | 356 | |
| 387 | _ = try self.addInst(.{ | 357 | _ = try self.addInst(.{ |
| 388 | .tag = .dbg_prologue_end, | 358 | .tag = .psuedo_prologue, |
| 389 | .data = .{ .nop = {} }, | 359 | .data = .{ .imm12 = 0 }, // Backpatched later. |
| 390 | }); | 360 | }); |
| 391 | | | |
| 392 | try self.genBody(self.air.getMainBody()); | | |
| 393 | | | |
| 394 | _ = try self.addInst(.{ | | |
| 395 | .tag = .dbg_epilogue_begin, | | |
| 396 | .data = .{ .nop = {} }, | | |
| 397 | }); | | |
| 398 | | | |
| 399 | // exitlude jumps | | |
| 400 | if (self.exitlude_jump_relocs.items.len > 0 and | | |
| 401 | self.exitlude_jump_relocs.items[self.exitlude_jump_relocs.items.len - 1] == self.mir_instructions.len - 2) | | |
| 402 | { | | |
| 403 | // If the last Mir instruction (apart from the | | |
| 404 | // dbg_epilogue_begin) is the last exitlude jump | | |
| 405 | // relocation (which would just jump one instruction | | |
| 406 | // further), it can be safely removed | | |
| 407 | self.mir_instructions.orderedRemove(self.exitlude_jump_relocs.pop()); | | |
| 408 | } | | |
| 409 | | | |
| 410 | for (self.exitlude_jump_relocs.items) |jmp_reloc| { | | |
| 411 | _ = jmp_reloc; | | |
| 412 | return self.fail("TODO add branches in RISCV64", .{}); | | |
| 413 | } | | |
| 414 | | 361 | |
| 415 | // ld ra, 8(sp) | 362 | _ = try self.addInst(.{ |
| 416 | _ = try self.addInst(.{ | 363 | .tag = .dbg_prologue_end, |
| 417 | .tag = .ld, | 364 | .data = .{ .nop = {} }, |
| 418 | .data = .{ .i_type = .{ | 365 | }); |
| 419 | .rd = .ra, | | |
| 420 | .rs1 = .sp, | | |
| 421 | .imm12 = 8, | | |
| 422 | } }, | | |
| 423 | }); | | |
| 424 | | 366 | |
| 425 | // ld s0, 0(sp) | 367 | try self.genBody(self.air.getMainBody()); |
| 426 | _ = try self.addInst(.{ | | |
| 427 | .tag = .ld, | | |
| 428 | .data = .{ .i_type = .{ | | |
| 429 | .rd = .s0, | | |
| 430 | .rs1 = .sp, | | |
| 431 | .imm12 = 0, | | |
| 432 | } }, | | |
| 433 | }); | | |
| 434 | | 368 | |
| 435 | // addi sp, sp, 16 | 369 | // Backpatch prologue stack size |
| 436 | _ = try self.addInst(.{ | 370 | if (math.cast(i12, self.max_end_stack)) |casted_stack_size| { |
| 437 | .tag = .addi, | 371 | self.mir_instructions.items(.data)[0].imm12 = casted_stack_size; |
| 438 | .data = .{ .i_type = .{ | 372 | } else return self.fail("TODO support larger stack sizes, got {}", .{self.max_end_stack}); |
| 439 | .rd = .sp, | | |
| 440 | .rs1 = .sp, | | |
| 441 | .imm12 = 16, | | |
| 442 | } }, | | |
| 443 | }); | | |
| 444 | | 373 | |
| 445 | // ret | 374 | _ = try self.addInst(.{ |
| 446 | _ = try self.addInst(.{ | 375 | .tag = .dbg_epilogue_begin, |
| 447 | .tag = .ret, | 376 | .data = .{ .nop = {} }, |
| 448 | .data = .{ .nop = {} }, | 377 | }); |
| 449 | }); | | |
| 450 | } else { | | |
| 451 | _ = try self.addInst(.{ | | |
| 452 | .tag = .dbg_prologue_end, | | |
| 453 | .data = .{ .nop = {} }, | | |
| 454 | }); | | |
| 455 | | 378 | |
| 456 | try self.genBody(self.air.getMainBody()); | 379 | // exitlude jumps |
| | 380 | if (self.exitlude_jump_relocs.items.len > 0 and |
| | 381 | self.exitlude_jump_relocs.items[self.exitlude_jump_relocs.items.len - 1] == self.mir_instructions.len - 2) |
| | 382 | { |
| | 383 | // If the last Mir instruction (apart from the |
| | 384 | // dbg_epilogue_begin) is the last exitlude jump |
| | 385 | // relocation (which would just jump one instruction |
| | 386 | // further), it can be safely removed |
| | 387 | self.mir_instructions.orderedRemove(self.exitlude_jump_relocs.pop()); |
| | 388 | } |
| 457 | | 389 | |
| 458 | _ = try self.addInst(.{ | 390 | for (self.exitlude_jump_relocs.items) |jmp_reloc| { |
| 459 | .tag = .dbg_epilogue_begin, | 391 | _ = jmp_reloc; |
| 460 | .data = .{ .nop = {} }, | 392 | return self.fail("TODO add branches in RISCV64", .{}); |
| 461 | }); | | |
| 462 | } | 393 | } |
| 463 | | 394 | |
| 464 | // Drop them off at the rbrace. | 395 | // Drop them off at the rbrace. |
| ... | @@ -535,12 +466,12 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -535,12 +466,12 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 535 | | 466 | |
| 536 | .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst), | 467 | .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst), |
| 537 | | 468 | |
| 538 | .cmp_lt => try self.airCmp(inst, .lt), | 469 | .cmp_lt => try self.airCmp(inst), |
| 539 | .cmp_lte => try self.airCmp(inst, .lte), | 470 | .cmp_lte => try self.airCmp(inst), |
| 540 | .cmp_eq => try self.airCmp(inst, .eq), | 471 | .cmp_eq => try self.airCmp(inst), |
| 541 | .cmp_gte => try self.airCmp(inst, .gte), | 472 | .cmp_gte => try self.airCmp(inst), |
| 542 | .cmp_gt => try self.airCmp(inst, .gt), | 473 | .cmp_gt => try self.airCmp(inst), |
| 543 | .cmp_neq => try self.airCmp(inst, .neq), | 474 | .cmp_neq => try self.airCmp(inst), |
| 544 | | 475 | |
| 545 | .cmp_vector => try self.airCmpVector(inst), | 476 | .cmp_vector => try self.airCmpVector(inst), |
| 546 | .cmp_lt_errors_len => try self.airCmpLtErrorsLen(inst), | 477 | .cmp_lt_errors_len => try self.airCmpLtErrorsLen(inst), |
| ... | @@ -565,6 +496,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -565,6 +496,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 565 | .frame_addr => try self.airFrameAddress(inst), | 496 | .frame_addr => try self.airFrameAddress(inst), |
| 566 | .fence => try self.airFence(), | 497 | .fence => try self.airFence(), |
| 567 | .cond_br => try self.airCondBr(inst), | 498 | .cond_br => try self.airCondBr(inst), |
| | 499 | .dbg_stmt => try self.airDbgStmt(inst), |
| 568 | .fptrunc => try self.airFptrunc(inst), | 500 | .fptrunc => try self.airFptrunc(inst), |
| 569 | .fpext => try self.airFpext(inst), | 501 | .fpext => try self.airFpext(inst), |
| 570 | .intcast => try self.airIntCast(inst), | 502 | .intcast => try self.airIntCast(inst), |
| ... | @@ -617,17 +549,17 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -617,17 +549,17 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 617 | .union_init => try self.airUnionInit(inst), | 549 | .union_init => try self.airUnionInit(inst), |
| 618 | .prefetch => try self.airPrefetch(inst), | 550 | .prefetch => try self.airPrefetch(inst), |
| 619 | .mul_add => try self.airMulAdd(inst), | 551 | .mul_add => try self.airMulAdd(inst), |
| 620 | .addrspace_cast => @panic("TODO"), | 552 | .addrspace_cast => return self.fail("TODO: addrspace_cast", .{}), |
| 621 | | 553 | |
| 622 | .@"try" => @panic("TODO"), | 554 | .@"try" => return self.fail("TODO: try", .{}), |
| 623 | .try_ptr => @panic("TODO"), | 555 | .try_ptr => return self.fail("TODO: try_ptr", .{}), |
| 624 | | 556 | |
| 625 | .dbg_stmt => try self.airDbgStmt(inst), | | |
| 626 | .dbg_inline_block => try self.airDbgInlineBlock(inst), | | |
| 627 | .dbg_var_ptr, | 557 | .dbg_var_ptr, |
| 628 | .dbg_var_val, | 558 | .dbg_var_val, |
| 629 | => try self.airDbgVar(inst), | 559 | => try self.airDbgVar(inst), |
| 630 | | 560 | |
| | 561 | .dbg_inline_block => try self.airDbgInlineBlock(inst), |
| | 562 | |
| 631 | .call => try self.airCall(inst, .auto), | 563 | .call => try self.airCall(inst, .auto), |
| 632 | .call_always_tail => try self.airCall(inst, .always_tail), | 564 | .call_always_tail => try self.airCall(inst, .always_tail), |
| 633 | .call_never_tail => try self.airCall(inst, .never_tail), | 565 | .call_never_tail => try self.airCall(inst, .never_tail), |
| ... | @@ -1019,17 +951,20 @@ fn binOpRegister( | ... | @@ -1019,17 +951,20 @@ fn binOpRegister( |
| 1019 | const mir_tag: Mir.Inst.Tag = switch (tag) { | 951 | const mir_tag: Mir.Inst.Tag = switch (tag) { |
| 1020 | .add => .add, | 952 | .add => .add, |
| 1021 | .sub => .sub, | 953 | .sub => .sub, |
| 1022 | else => unreachable, | 954 | .cmp_eq => .cmp_eq, |
| | 955 | .cmp_gt => .cmp_gt, |
| | 956 | else => return self.fail("TODO: binOpRegister {s}", .{@tagName(tag)}), |
| 1023 | }; | 957 | }; |
| 1024 | const mir_data: Mir.Inst.Data = switch (tag) { | 958 | const mir_data: Mir.Inst.Data = switch (tag) { |
| 1025 | .add, | 959 | .add, |
| 1026 | .sub, | 960 | .sub, |
| | 961 | .cmp_eq, |
| 1027 | => .{ .r_type = .{ | 962 | => .{ .r_type = .{ |
| 1028 | .rd = dest_reg, | 963 | .rd = dest_reg, |
| 1029 | .rs1 = lhs_reg, | 964 | .rs1 = lhs_reg, |
| 1030 | .rs2 = rhs_reg, | 965 | .rs2 = rhs_reg, |
| 1031 | } }, | 966 | } }, |
| 1032 | else => unreachable, | 967 | else => return self.fail("TODO: binOpRegister {s}", .{@tagName(tag)}), |
| 1033 | }; | 968 | }; |
| 1034 | | 969 | |
| 1035 | _ = try self.addInst(.{ | 970 | _ = try self.addInst(.{ |
| ... | @@ -1052,6 +987,8 @@ fn binOpRegister( | ... | @@ -1052,6 +987,8 @@ fn binOpRegister( |
| 1052 | /// looks at the lhs and rhs and determines which kind of lowering | 987 | /// looks at the lhs and rhs and determines which kind of lowering |
| 1053 | /// would be best suitable and then delegates the lowering to other | 988 | /// would be best suitable and then delegates the lowering to other |
| 1054 | /// functions. | 989 | /// functions. |
| | 990 | /// |
| | 991 | /// `maybe_inst` **needs** to be a bin_op, make sure of that. |
| 1055 | fn binOp( | 992 | fn binOp( |
| 1056 | self: *Self, | 993 | self: *Self, |
| 1057 | tag: Air.Inst.Tag, | 994 | tag: Air.Inst.Tag, |
| ... | @@ -1066,6 +1003,12 @@ fn binOp( | ... | @@ -1066,6 +1003,12 @@ fn binOp( |
| 1066 | // Arithmetic operations on integers and floats | 1003 | // Arithmetic operations on integers and floats |
| 1067 | .add, | 1004 | .add, |
| 1068 | .sub, | 1005 | .sub, |
| | 1006 | .cmp_eq, |
| | 1007 | .cmp_neq, |
| | 1008 | .cmp_gt, |
| | 1009 | .cmp_gte, |
| | 1010 | .cmp_lt, |
| | 1011 | .cmp_lte, |
| 1069 | => { | 1012 | => { |
| 1070 | switch (lhs_ty.zigTypeTag(mod)) { | 1013 | switch (lhs_ty.zigTypeTag(mod)) { |
| 1071 | .Float => return self.fail("TODO binary operations on floats", .{}), | 1014 | .Float => return self.fail("TODO binary operations on floats", .{}), |
| ... | @@ -1180,8 +1123,19 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1180,8 +1123,19 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void { |
| 1180 | } | 1123 | } |
| 1181 | | 1124 | |
| 1182 | fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | 1125 | fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1183 | _ = inst; | 1126 | const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| 1184 | return self.fail("TODO implement airAddWithOverflow for {}", .{self.target.cpu.arch}); | 1127 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| | 1128 | |
| | 1129 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| | 1130 | const lhs = try self.resolveInst(extra.lhs); |
| | 1131 | const rhs = try self.resolveInst(extra.rhs); |
| | 1132 | const lhs_ty = self.typeOf(extra.lhs); |
| | 1133 | const rhs_ty = self.typeOf(extra.rhs); |
| | 1134 | |
| | 1135 | break :result try self.binOp(.add, null, lhs, rhs, lhs_ty, rhs_ty); |
| | 1136 | }; |
| | 1137 | |
| | 1138 | return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none }); |
| 1185 | } | 1139 | } |
| 1186 | | 1140 | |
| 1187 | fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | 1141 | fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| ... | @@ -1352,13 +1306,30 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1352,13 +1306,30 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { |
| 1352 | | 1306 | |
| 1353 | fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void { | 1307 | fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1354 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; | 1308 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 1355 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement slice_ptr for {}", .{self.target.cpu.arch}); | 1309 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| | 1310 | const mcv = try self.resolveInst(ty_op.operand); |
| | 1311 | break :result try self.slicePtr(mcv); |
| | 1312 | }; |
| 1356 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 1313 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1357 | } | 1314 | } |
| 1358 | | 1315 | |
| | 1316 | fn slicePtr(self: *Self, mcv: MCValue) !MCValue { |
| | 1317 | switch (mcv) { |
| | 1318 | .dead, .unreach, .none => unreachable, |
| | 1319 | .register => unreachable, // a slice doesn't fit in one register |
| | 1320 | .stack_offset => |off| { |
| | 1321 | return MCValue{ .stack_offset = off }; |
| | 1322 | }, |
| | 1323 | .memory => |addr| { |
| | 1324 | return MCValue{ .memory = addr }; |
| | 1325 | }, |
| | 1326 | else => return self.fail("TODO slicePtr {s}", .{@tagName(mcv)}), |
| | 1327 | } |
| | 1328 | } |
| | 1329 | |
| 1359 | fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void { | 1330 | fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void { |
| 1360 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; | 1331 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 1361 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement slice_len for {}", .{self.target.cpu.arch}); | 1332 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airSliceLen for {}", .{self.target.cpu.arch}); |
| 1362 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 1333 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1363 | } | 1334 | } |
| 1364 | | 1335 | |
| ... | @@ -1500,6 +1471,7 @@ fn reuseOperand(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, op_ind | ... | @@ -1500,6 +1471,7 @@ fn reuseOperand(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, op_ind |
| 1500 | fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!void { | 1471 | fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!void { |
| 1501 | const mod = self.bin_file.comp.module.?; | 1472 | const mod = self.bin_file.comp.module.?; |
| 1502 | const elem_ty = ptr_ty.childType(mod); | 1473 | const elem_ty = ptr_ty.childType(mod); |
| | 1474 | |
| 1503 | switch (ptr) { | 1475 | switch (ptr) { |
| 1504 | .none => unreachable, | 1476 | .none => unreachable, |
| 1505 | .undef => unreachable, | 1477 | .undef => unreachable, |
| ... | @@ -1507,9 +1479,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo | ... | @@ -1507,9 +1479,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 1507 | .dead => unreachable, | 1479 | .dead => unreachable, |
| 1508 | .immediate => |imm| try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm }), | 1480 | .immediate => |imm| try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm }), |
| 1509 | .ptr_stack_offset => |off| try self.setRegOrMem(elem_ty, dst_mcv, .{ .stack_offset = off }), | 1481 | .ptr_stack_offset => |off| try self.setRegOrMem(elem_ty, dst_mcv, .{ .stack_offset = off }), |
| 1510 | .register => { | 1482 | .register => |src_reg| try self.setRegOrMem(elem_ty, dst_mcv, .{ .register = src_reg }), |
| 1511 | return self.fail("TODO implement loading from MCValue.register", .{}); | | |
| 1512 | }, | | |
| 1513 | .memory, | 1483 | .memory, |
| 1514 | .stack_offset, | 1484 | .stack_offset, |
| 1515 | => { | 1485 | => { |
| ... | @@ -1520,6 +1490,10 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo | ... | @@ -1520,6 +1490,10 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 1520 | try self.genSetReg(ptr_ty, reg, ptr); | 1490 | try self.genSetReg(ptr_ty, reg, ptr); |
| 1521 | try self.load(dst_mcv, .{ .register = reg }, ptr_ty); | 1491 | try self.load(dst_mcv, .{ .register = reg }, ptr_ty); |
| 1522 | }, | 1492 | }, |
| | 1493 | .load_symbol => { |
| | 1494 | const reg = try self.copyToTmpRegister(ptr_ty, ptr); |
| | 1495 | try self.load(dst_mcv, .{ .register = reg }, ptr_ty); |
| | 1496 | }, |
| 1523 | } | 1497 | } |
| 1524 | } | 1498 | } |
| 1525 | | 1499 | |
| ... | @@ -1553,6 +1527,8 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1553,6 +1527,8 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 1553 | fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type) !void { | 1527 | fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type) !void { |
| 1554 | _ = ptr_ty; | 1528 | _ = ptr_ty; |
| 1555 | | 1529 | |
| | 1530 | log.debug("storing {s}", .{@tagName(ptr)}); |
| | 1531 | |
| 1556 | switch (ptr) { | 1532 | switch (ptr) { |
| 1557 | .none => unreachable, | 1533 | .none => unreachable, |
| 1558 | .undef => unreachable, | 1534 | .undef => unreachable, |
| ... | @@ -1573,6 +1549,9 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type | ... | @@ -1573,6 +1549,9 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 1573 | .stack_offset => { | 1549 | .stack_offset => { |
| 1574 | return self.fail("TODO implement storing to MCValue.stack_offset", .{}); | 1550 | return self.fail("TODO implement storing to MCValue.stack_offset", .{}); |
| 1575 | }, | 1551 | }, |
| | 1552 | .load_symbol => { |
| | 1553 | return self.fail("TODO implement storing to MCValue.load_symbol", .{}); |
| | 1554 | }, |
| 1576 | } | 1555 | } |
| 1577 | } | 1556 | } |
| 1578 | | 1557 | |
| ... | @@ -1596,27 +1575,32 @@ fn airStore(self: *Self, inst: Air.Inst.Index, safety: bool) !void { | ... | @@ -1596,27 +1575,32 @@ fn airStore(self: *Self, inst: Air.Inst.Index, safety: bool) !void { |
| 1596 | fn airStructFieldPtr(self: *Self, inst: Air.Inst.Index) !void { | 1575 | fn airStructFieldPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1597 | const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; | 1576 | const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| 1598 | const extra = self.air.extraData(Air.StructField, ty_pl.payload).data; | 1577 | const extra = self.air.extraData(Air.StructField, ty_pl.payload).data; |
| 1599 | return self.structFieldPtr(extra.struct_operand, ty_pl.ty, extra.field_index); | 1578 | const result = try self.structFieldPtr(inst, extra.struct_operand, ty_pl.ty, extra.field_index); |
| | 1579 | return self.finishAir(inst, result, .{ extra.struct_operand, .none, .none }); |
| 1600 | } | 1580 | } |
| 1601 | | 1581 | |
| 1602 | fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u8) !void { | 1582 | fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u8) !void { |
| 1603 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; | 1583 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 1604 | return self.structFieldPtr(ty_op.operand, ty_op.ty, index); | 1584 | const result = try self.structFieldPtr(inst, ty_op.operand, ty_op.ty, index); |
| | 1585 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1605 | } | 1586 | } |
| 1606 | fn structFieldPtr(self: *Self, operand: Air.Inst.Ref, ty: Air.Inst.Ref, index: u32) !void { | 1587 | |
| | 1588 | fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, ty: Air.Inst.Ref, index: u32) !MCValue { |
| | 1589 | _ = inst; |
| 1607 | _ = operand; | 1590 | _ = operand; |
| 1608 | _ = ty; | 1591 | _ = ty; |
| 1609 | _ = index; | 1592 | _ = index; |
| 1610 | return self.fail("TODO implement codegen struct_field_ptr", .{}); | 1593 | |
| 1611 | //return self.finishAir(inst, result, .{ extra.struct_ptr, .none, .none }); | 1594 | return self.fail("TODO: structFieldPtr", .{}); |
| 1612 | } | 1595 | } |
| 1613 | | 1596 | |
| 1614 | fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { | 1597 | fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 1615 | const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; | 1598 | const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| 1616 | const extra = self.air.extraData(Air.StructField, ty_pl.payload).data; | 1599 | _ = ty_pl; |
| 1617 | _ = extra; | 1600 | |
| 1618 | return self.fail("TODO implement codegen struct_field_val", .{}); | 1601 | return self.fail("TODO: airStructFieldVal", .{}); |
| 1619 | //return self.finishAir(inst, result, .{ extra.struct_ptr, .none, .none }); | 1602 | |
| | 1603 | // return self.finishAir(inst, result, .{ extra.struct_operand, .none, .none }); |
| 1620 | } | 1604 | } |
| 1621 | | 1605 | |
| 1622 | fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void { | 1606 | fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void { |
| ... | @@ -1732,12 +1716,13 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier | ... | @@ -1732,12 +1716,13 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 1732 | try self.register_manager.getReg(reg, null); | 1716 | try self.register_manager.getReg(reg, null); |
| 1733 | try self.genSetReg(arg_ty, reg, arg_mcv); | 1717 | try self.genSetReg(arg_ty, reg, arg_mcv); |
| 1734 | }, | 1718 | }, |
| 1735 | .stack_offset => { | 1719 | .stack_offset => |off| try self.genSetStack(arg_ty, off, arg_mcv), |
| 1736 | return self.fail("TODO implement calling with parameters in memory", .{}); | | |
| 1737 | }, | | |
| 1738 | .ptr_stack_offset => { | 1720 | .ptr_stack_offset => { |
| 1739 | return self.fail("TODO implement calling with MCValue.ptr_stack_offset arg", .{}); | 1721 | return self.fail("TODO implement calling with MCValue.ptr_stack_offset arg", .{}); |
| 1740 | }, | 1722 | }, |
| | 1723 | .load_symbol => { |
| | 1724 | return self.fail("TODO implement calling with MCValue.load_symbol", .{}); |
| | 1725 | }, |
| 1741 | } | 1726 | } |
| 1742 | } | 1727 | } |
| 1743 | | 1728 | |
| ... | @@ -1747,7 +1732,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier | ... | @@ -1747,7 +1732,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 1747 | const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, func.owner_decl); | 1732 | const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, func.owner_decl); |
| 1748 | const sym = elf_file.symbol(sym_index); | 1733 | const sym = elf_file.symbol(sym_index); |
| 1749 | _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file); | 1734 | _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file); |
| 1750 | const got_addr: u32 = @intCast(sym.zigGotAddress(elf_file)); | 1735 | const got_addr = sym.zigGotAddress(elf_file); |
| 1751 | try self.genSetReg(Type.usize, .ra, .{ .memory = got_addr }); | 1736 | try self.genSetReg(Type.usize, .ra, .{ .memory = got_addr }); |
| 1752 | _ = try self.addInst(.{ | 1737 | _ = try self.addInst(.{ |
| 1753 | .tag = .jalr, | 1738 | .tag = .jalr, |
| ... | @@ -1830,7 +1815,8 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1830,7 +1815,8 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 1830 | //return self.finishAir(inst, .dead, .{ un_op, .none, .none }); | 1815 | //return self.finishAir(inst, .dead, .{ un_op, .none, .none }); |
| 1831 | } | 1816 | } |
| 1832 | | 1817 | |
| 1833 | fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { | 1818 | fn airCmp(self: *Self, inst: Air.Inst.Index) !void { |
| | 1819 | const tag = self.air.instructions.items(.tag)[@intFromEnum(inst)]; |
| 1834 | const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; | 1820 | const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| 1835 | if (self.liveness.isUnused(inst)) | 1821 | if (self.liveness.isUnused(inst)) |
| 1836 | return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); | 1822 | return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); |
| ... | @@ -1842,12 +1828,12 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { | ... | @@ -1842,12 +1828,12 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 1842 | | 1828 | |
| 1843 | const lhs = try self.resolveInst(bin_op.lhs); | 1829 | const lhs = try self.resolveInst(bin_op.lhs); |
| 1844 | const rhs = try self.resolveInst(bin_op.rhs); | 1830 | const rhs = try self.resolveInst(bin_op.rhs); |
| 1845 | _ = op; | 1831 | const lhs_ty = self.typeOf(bin_op.lhs); |
| 1846 | _ = lhs; | 1832 | const rhs_ty = self.typeOf(bin_op.rhs); |
| 1847 | _ = rhs; | | |
| 1848 | | 1833 | |
| 1849 | return self.fail("TODO implement cmp for {}", .{self.target.cpu.arch}); | 1834 | const result = try self.binOp(tag, null, lhs, rhs, lhs_ty, rhs_ty); |
| 1850 | // return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 1835 | |
| | 1836 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1851 | } | 1837 | } |
| 1852 | | 1838 | |
| 1853 | fn airCmpVector(self: *Self, inst: Air.Inst.Index) !void { | 1839 | fn airCmpVector(self: *Self, inst: Air.Inst.Index) !void { |
| ... | @@ -1878,13 +1864,11 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1878,13 +1864,11 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void { |
| 1878 | } | 1864 | } |
| 1879 | | 1865 | |
| 1880 | fn airDbgInlineBlock(self: *Self, inst: Air.Inst.Index) !void { | 1866 | fn airDbgInlineBlock(self: *Self, inst: Air.Inst.Index) !void { |
| 1881 | const mod = self.bin_file.comp.module.?; | | |
| 1882 | const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; | 1867 | const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| 1883 | const extra = self.air.extraData(Air.DbgInlineBlock, ty_pl.payload); | 1868 | const extra = self.air.extraData(Air.DbgInlineBlock, ty_pl.payload); |
| 1884 | const func = mod.funcInfo(extra.data.func); | 1869 | _ = extra; |
| 1885 | // TODO emit debug info for function change | 1870 | // TODO: emit debug info for this block |
| 1886 | _ = func; | 1871 | return self.finishAir(inst, .dead, .{ .none, .none, .none }); |
| 1887 | try self.lowerBlock(inst, @ptrCast(self.air.extra[extra.end..][0..extra.data.body_len])); | | |
| 1888 | } | 1872 | } |
| 1889 | | 1873 | |
| 1890 | fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { | 1874 | fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { |
| ... | @@ -1897,10 +1881,165 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1897,10 +1881,165 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { |
| 1897 | } | 1881 | } |
| 1898 | | 1882 | |
| 1899 | fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { | 1883 | fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 1900 | _ = inst; | 1884 | const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; |
| | 1885 | const cond = try self.resolveInst(pl_op.operand); |
| | 1886 | const cond_ty = self.typeOf(pl_op.operand); |
| | 1887 | const extra = self.air.extraData(Air.CondBr, pl_op.payload); |
| | 1888 | const then_body: []const Air.Inst.Index = @ptrCast(self.air.extra[extra.end..][0..extra.data.then_body_len]); |
| | 1889 | const else_body: []const Air.Inst.Index = @ptrCast(self.air.extra[extra.end + then_body.len ..][0..extra.data.else_body_len]); |
| | 1890 | const liveness_condbr = self.liveness.getCondBr(inst); |
| | 1891 | |
| | 1892 | // A branch to the false section. Uses beq |
| | 1893 | const reloc = try self.condBr(cond_ty, cond); |
| | 1894 | |
| | 1895 | // If the condition dies here in this condbr instruction, process |
| | 1896 | // that death now instead of later as this has an effect on |
| | 1897 | // whether it needs to be spilled in the branches |
| | 1898 | if (self.liveness.operandDies(inst, 0)) { |
| | 1899 | if (pl_op.operand.toIndex()) |op_index| { |
| | 1900 | self.processDeath(op_index); |
| | 1901 | } |
| | 1902 | } |
| | 1903 | |
| | 1904 | // Save state |
| | 1905 | const parent_next_stack_offset = self.next_stack_offset; |
| | 1906 | const parent_free_registers = self.register_manager.free_registers; |
| | 1907 | var parent_stack = try self.stack.clone(self.gpa); |
| | 1908 | defer parent_stack.deinit(self.gpa); |
| | 1909 | const parent_registers = self.register_manager.registers; |
| | 1910 | |
| | 1911 | try self.branch_stack.append(.{}); |
| | 1912 | errdefer { |
| | 1913 | _ = self.branch_stack.pop(); |
| | 1914 | } |
| | 1915 | |
| | 1916 | try self.ensureProcessDeathCapacity(liveness_condbr.then_deaths.len); |
| | 1917 | for (liveness_condbr.then_deaths) |operand| { |
| | 1918 | self.processDeath(operand); |
| | 1919 | } |
| | 1920 | try self.genBody(then_body); |
| | 1921 | |
| | 1922 | // Revert to the previous register and stack allocation state. |
| | 1923 | |
| | 1924 | var saved_then_branch = self.branch_stack.pop(); |
| | 1925 | defer saved_then_branch.deinit(self.gpa); |
| | 1926 | |
| | 1927 | self.register_manager.registers = parent_registers; |
| | 1928 | |
| | 1929 | self.stack.deinit(self.gpa); |
| | 1930 | self.stack = parent_stack; |
| | 1931 | parent_stack = .{}; |
| | 1932 | |
| | 1933 | self.next_stack_offset = parent_next_stack_offset; |
| | 1934 | self.register_manager.free_registers = parent_free_registers; |
| | 1935 | |
| | 1936 | try self.performReloc(reloc); |
| | 1937 | const else_branch = self.branch_stack.addOneAssumeCapacity(); |
| | 1938 | else_branch.* = .{}; |
| | 1939 | |
| | 1940 | try self.ensureProcessDeathCapacity(liveness_condbr.else_deaths.len); |
| | 1941 | for (liveness_condbr.else_deaths) |operand| { |
| | 1942 | self.processDeath(operand); |
| | 1943 | } |
| | 1944 | try self.genBody(else_body); |
| | 1945 | |
| | 1946 | // At this point, each branch will possibly have conflicting values for where |
| | 1947 | // each instruction is stored. They agree, however, on which instructions are alive/dead. |
| | 1948 | // We use the first ("then") branch as canonical, and here emit |
| | 1949 | // instructions into the second ("else") branch to make it conform. |
| | 1950 | // We continue respect the data structure semantic guarantees of the else_branch so |
| | 1951 | // that we can use all the code emitting abstractions. This is why at the bottom we |
| | 1952 | // assert that parent_branch.free_registers equals the saved_then_branch.free_registers |
| | 1953 | // rather than assigning it. |
| | 1954 | const parent_branch = &self.branch_stack.items[self.branch_stack.items.len - 2]; |
| | 1955 | try parent_branch.inst_table.ensureUnusedCapacity(self.gpa, else_branch.inst_table.count()); |
| | 1956 | const else_slice = else_branch.inst_table.entries.slice(); |
| | 1957 | const else_keys = else_slice.items(.key); |
| | 1958 | const else_values = else_slice.items(.value); |
| | 1959 | for (else_keys, 0..) |else_key, else_idx| { |
| | 1960 | const else_value = else_values[else_idx]; |
| | 1961 | const canon_mcv = if (saved_then_branch.inst_table.fetchSwapRemove(else_key)) |then_entry| blk: { |
| | 1962 | // The instruction's MCValue is overridden in both branches. |
| | 1963 | log.debug("condBr put branch table (key = %{d}, value = {})", .{ else_key, then_entry.value }); |
| | 1964 | parent_branch.inst_table.putAssumeCapacity(else_key, then_entry.value); |
| | 1965 | if (else_value == .dead) { |
| | 1966 | assert(then_entry.value == .dead); |
| | 1967 | continue; |
| | 1968 | } |
| | 1969 | break :blk then_entry.value; |
| | 1970 | } else blk: { |
| | 1971 | if (else_value == .dead) |
| | 1972 | continue; |
| | 1973 | // The instruction is only overridden in the else branch. |
| | 1974 | var i: usize = self.branch_stack.items.len - 2; |
| | 1975 | while (true) { |
| | 1976 | i -= 1; // If this overflows, the question is: why wasn't the instruction marked dead? |
| | 1977 | if (self.branch_stack.items[i].inst_table.get(else_key)) |mcv| { |
| | 1978 | assert(mcv != .dead); |
| | 1979 | break :blk mcv; |
| | 1980 | } |
| | 1981 | } |
| | 1982 | }; |
| | 1983 | log.debug("consolidating else_entry {d} {}=>{}", .{ else_key, else_value, canon_mcv }); |
| | 1984 | // TODO make sure the destination stack offset / register does not already have something |
| | 1985 | // going on there. |
| | 1986 | try self.setRegOrMem(self.typeOfIndex(else_key), canon_mcv, else_value); |
| | 1987 | // TODO track the new register / stack allocation |
| | 1988 | } |
| | 1989 | try parent_branch.inst_table.ensureUnusedCapacity(self.gpa, saved_then_branch.inst_table.count()); |
| | 1990 | const then_slice = saved_then_branch.inst_table.entries.slice(); |
| | 1991 | const then_keys = then_slice.items(.key); |
| | 1992 | const then_values = then_slice.items(.value); |
| | 1993 | for (then_keys, 0..) |then_key, then_idx| { |
| | 1994 | const then_value = then_values[then_idx]; |
| | 1995 | // We already deleted the items from this table that matched the else_branch. |
| | 1996 | // So these are all instructions that are only overridden in the then branch. |
| | 1997 | parent_branch.inst_table.putAssumeCapacity(then_key, then_value); |
| | 1998 | if (then_value == .dead) |
| | 1999 | continue; |
| | 2000 | const parent_mcv = blk: { |
| | 2001 | var i: usize = self.branch_stack.items.len - 2; |
| | 2002 | while (true) { |
| | 2003 | i -= 1; |
| | 2004 | if (self.branch_stack.items[i].inst_table.get(then_key)) |mcv| { |
| | 2005 | assert(mcv != .dead); |
| | 2006 | break :blk mcv; |
| | 2007 | } |
| | 2008 | } |
| | 2009 | }; |
| | 2010 | log.debug("consolidating then_entry {d} {}=>{}", .{ then_key, parent_mcv, then_value }); |
| | 2011 | // TODO make sure the destination stack offset / register does not already have something |
| | 2012 | // going on there. |
| | 2013 | try self.setRegOrMem(self.typeOfIndex(then_key), parent_mcv, then_value); |
| | 2014 | // TODO track the new register / stack allocation |
| | 2015 | } |
| 1901 | | 2016 | |
| 1902 | return self.fail("TODO implement condbr {}", .{self.target.cpu.arch}); | 2017 | { |
| 1903 | // return self.finishAir(inst, .unreach, .{ pl_op.operand, .none, .none }); | 2018 | var item = self.branch_stack.pop(); |
| | 2019 | item.deinit(self.gpa); |
| | 2020 | } |
| | 2021 | |
| | 2022 | return self.finishAir(inst, .unreach, .{ .none, .none, .none }); |
| | 2023 | } |
| | 2024 | |
| | 2025 | fn condBr(self: *Self, cond_ty: Type, condition: MCValue) !Mir.Inst.Index { |
| | 2026 | _ = cond_ty; |
| | 2027 | |
| | 2028 | const reg = switch (condition) { |
| | 2029 | .register => |r| r, |
| | 2030 | else => try self.copyToTmpRegister(Type.bool, condition), |
| | 2031 | }; |
| | 2032 | |
| | 2033 | return try self.addInst(.{ |
| | 2034 | .tag = .beq, |
| | 2035 | .data = .{ |
| | 2036 | .b_type = .{ |
| | 2037 | .rs1 = reg, |
| | 2038 | .rs2 = .zero, |
| | 2039 | .imm12 = 0, // patched later. |
| | 2040 | }, |
| | 2041 | }, |
| | 2042 | }); |
| 1904 | } | 2043 | } |
| 1905 | | 2044 | |
| 1906 | fn isNull(self: *Self, operand: MCValue) !MCValue { | 2045 | fn isNull(self: *Self, operand: MCValue) !MCValue { |
| ... | @@ -2044,25 +2183,26 @@ fn airLoop(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2044,25 +2183,26 @@ fn airLoop(self: *Self, inst: Air.Inst.Index) !void { |
| 2044 | const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; | 2183 | const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| 2045 | const loop = self.air.extraData(Air.Block, ty_pl.payload); | 2184 | const loop = self.air.extraData(Air.Block, ty_pl.payload); |
| 2046 | const body: []const Air.Inst.Index = @ptrCast(self.air.extra[loop.end..][0..loop.data.body_len]); | 2185 | const body: []const Air.Inst.Index = @ptrCast(self.air.extra[loop.end..][0..loop.data.body_len]); |
| 2047 | const start_index = self.code.items.len; | 2186 | |
| | 2187 | const start_index: Mir.Inst.Index = @intCast(self.code.items.len); |
| | 2188 | |
| 2048 | try self.genBody(body); | 2189 | try self.genBody(body); |
| 2049 | try self.jump(start_index); | 2190 | try self.jump(start_index); |
| | 2191 | |
| 2050 | return self.finishAirBookkeeping(); | 2192 | return self.finishAirBookkeeping(); |
| 2051 | } | 2193 | } |
| 2052 | | 2194 | |
| 2053 | /// Send control flow to the `index` of `self.code`. | 2195 | /// Send control flow to the `index` of `self.code`. |
| 2054 | fn jump(self: *Self, index: usize) !void { | 2196 | fn jump(self: *Self, index: Mir.Inst.Index) !void { |
| 2055 | _ = index; | 2197 | _ = try self.addInst(.{ |
| 2056 | return self.fail("TODO implement jump for {}", .{self.target.cpu.arch}); | 2198 | .tag = .psuedo_jump, |
| | 2199 | .data = .{ |
| | 2200 | .inst = index, |
| | 2201 | }, |
| | 2202 | }); |
| 2057 | } | 2203 | } |
| 2058 | | 2204 | |
| 2059 | fn airBlock(self: *Self, inst: Air.Inst.Index) !void { | 2205 | fn airBlock(self: *Self, inst: Air.Inst.Index) !void { |
| 2060 | const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; | | |
| 2061 | const extra = self.air.extraData(Air.Block, ty_pl.payload); | | |
| 2062 | try self.lowerBlock(inst, @ptrCast(self.air.extra[extra.end..][0..extra.data.body_len])); | | |
| 2063 | } | | |
| 2064 | | | |
| 2065 | fn lowerBlock(self: *Self, inst: Air.Inst.Index, body: []const Air.Inst.Index) !void { | | |
| 2066 | try self.blocks.putNoClobber(self.gpa, inst, .{ | 2206 | try self.blocks.putNoClobber(self.gpa, inst, .{ |
| 2067 | // A block is a setup to be able to jump to the end. | 2207 | // A block is a setup to be able to jump to the end. |
| 2068 | .relocs = .{}, | 2208 | .relocs = .{}, |
| ... | @@ -2074,10 +2214,16 @@ fn lowerBlock(self: *Self, inst: Air.Inst.Index, body: []const Air.Inst.Index) ! | ... | @@ -2074,10 +2214,16 @@ fn lowerBlock(self: *Self, inst: Air.Inst.Index, body: []const Air.Inst.Index) ! |
| 2074 | .mcv = MCValue{ .none = {} }, | 2214 | .mcv = MCValue{ .none = {} }, |
| 2075 | }); | 2215 | }); |
| 2076 | defer self.blocks.getPtr(inst).?.relocs.deinit(self.gpa); | 2216 | defer self.blocks.getPtr(inst).?.relocs.deinit(self.gpa); |
| | 2217 | |
| | 2218 | const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| | 2219 | const extra = self.air.extraData(Air.Block, ty_pl.payload); |
| | 2220 | const body: []const Air.Inst.Index = @ptrCast(self.air.extra[extra.end..][0..extra.data.body_len]); |
| 2077 | // TODO emit debug info lexical block | 2221 | // TODO emit debug info lexical block |
| 2078 | try self.genBody(body); | 2222 | try self.genBody(body); |
| 2079 | | 2223 | |
| 2080 | for (self.blocks.getPtr(inst).?.relocs.items) |reloc| try self.performReloc(reloc); | 2224 | for (self.blocks.getPtr(inst).?.relocs.items) |reloc| { |
| | 2225 | try self.performReloc(reloc); |
| | 2226 | } |
| 2081 | | 2227 | |
| 2082 | const result = self.blocks.getPtr(inst).?.mcv; | 2228 | const result = self.blocks.getPtr(inst).?.mcv; |
| 2083 | return self.finishAir(inst, result, .{ .none, .none, .none }); | 2229 | return self.finishAir(inst, result, .{ .none, .none, .none }); |
| ... | @@ -2091,11 +2237,12 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2091,11 +2237,12 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void { |
| 2091 | // return self.finishAir(inst, .dead, .{ condition, .none, .none }); | 2237 | // return self.finishAir(inst, .dead, .{ condition, .none, .none }); |
| 2092 | } | 2238 | } |
| 2093 | | 2239 | |
| 2094 | fn performReloc(self: *Self, reloc: Reloc) !void { | 2240 | fn performReloc(self: *Self, inst: Mir.Inst.Index) !void { |
| 2095 | _ = self; | 2241 | const tag = self.mir_instructions.items(.tag)[inst]; |
| 2096 | switch (reloc) { | 2242 | |
| 2097 | .rel32 => unreachable, | 2243 | switch (tag) { |
| 2098 | .arm_branch => unreachable, | 2244 | .beq => self.mir_instructions.items(.data)[inst].b_type.imm12 = @intCast(inst), |
| | 2245 | else => return self.fail("TODO: performReloc {s}", .{@tagName(tag)}), |
| 2099 | } | 2246 | } |
| 2100 | } | 2247 | } |
| 2101 | | 2248 | |
| ... | @@ -2135,7 +2282,15 @@ fn brVoid(self: *Self, block: Air.Inst.Index) !void { | ... | @@ -2135,7 +2282,15 @@ fn brVoid(self: *Self, block: Air.Inst.Index) !void { |
| 2135 | // Emit a jump with a relocation. It will be patched up after the block ends. | 2282 | // Emit a jump with a relocation. It will be patched up after the block ends. |
| 2136 | try block_data.relocs.ensureUnusedCapacity(self.gpa, 1); | 2283 | try block_data.relocs.ensureUnusedCapacity(self.gpa, 1); |
| 2137 | | 2284 | |
| 2138 | return self.fail("TODO implement brvoid for {}", .{self.target.cpu.arch}); | 2285 | block_data.relocs.appendAssumeCapacity(try self.addInst(.{ |
| | 2286 | .tag = .jal, |
| | 2287 | .data = .{ |
| | 2288 | .j_type = .{ |
| | 2289 | .rd = .ra, |
| | 2290 | .imm21 = undefined, // populated later through performReloc |
| | 2291 | }, |
| | 2292 | }, |
| | 2293 | })); |
| 2139 | } | 2294 | } |
| 2140 | | 2295 | |
| 2141 | fn airAsm(self: *Self, inst: Air.Inst.Index) !void { | 2296 | fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| ... | @@ -2261,28 +2416,138 @@ fn iterateBigTomb(self: *Self, inst: Air.Inst.Index, operand_count: usize) !BigT | ... | @@ -2261,28 +2416,138 @@ fn iterateBigTomb(self: *Self, inst: Air.Inst.Index, operand_count: usize) !BigT |
| 2261 | | 2416 | |
| 2262 | /// Sets the value without any modifications to register allocation metadata or stack allocation metadata. | 2417 | /// Sets the value without any modifications to register allocation metadata or stack allocation metadata. |
| 2263 | fn setRegOrMem(self: *Self, ty: Type, loc: MCValue, val: MCValue) !void { | 2418 | fn setRegOrMem(self: *Self, ty: Type, loc: MCValue, val: MCValue) !void { |
| | 2419 | if (!loc.isMutable()) { |
| | 2420 | return std.debug.panic("tried to setRegOrMem immutable: {s}", .{@tagName(loc)}); |
| | 2421 | } |
| | 2422 | |
| 2264 | switch (loc) { | 2423 | switch (loc) { |
| 2265 | .none => return, | 2424 | .none => return, |
| 2266 | .register => |reg| return self.genSetReg(ty, reg, val), | 2425 | .register => |reg| return self.genSetReg(ty, reg, val), |
| 2267 | .stack_offset => |off| return self.genSetStack(ty, off, val), | 2426 | .stack_offset => |off| return self.genSetStack(ty, off, val), |
| 2268 | .memory => { | 2427 | else => return self.fail("TODO: setRegOrMem {s}", .{@tagName(loc)}), |
| 2269 | return self.fail("TODO implement setRegOrMem for memory", .{}); | | |
| 2270 | }, | | |
| 2271 | else => unreachable, | | |
| 2272 | } | 2428 | } |
| 2273 | } | 2429 | } |
| 2274 | | 2430 | |
| 2275 | fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerError!void { | 2431 | fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerError!void { |
| 2276 | _ = ty; | 2432 | const mod = self.bin_file.comp.module.?; |
| 2277 | _ = stack_offset; | 2433 | const abi_size: u32 = @intCast(ty.abiSize(mod)); |
| 2278 | _ = mcv; | 2434 | |
| 2279 | return self.fail("TODO implement getSetStack for {}", .{self.target.cpu.arch}); | 2435 | switch (mcv) { |
| | 2436 | .none => return, |
| | 2437 | .dead => unreachable, |
| | 2438 | .immediate => { |
| | 2439 | const reg = try self.copyToTmpRegister(ty, mcv); |
| | 2440 | return self.genSetStack(ty, stack_offset, .{ .register = reg }); |
| | 2441 | }, |
| | 2442 | .register => |reg| { |
| | 2443 | switch (abi_size) { |
| | 2444 | 1, 2, 4, 8 => { |
| | 2445 | assert(std.mem.isAlignedGeneric(u32, stack_offset, abi_size)); |
| | 2446 | |
| | 2447 | const tag: Mir.Inst.Tag = switch (abi_size) { |
| | 2448 | 1 => .sb, |
| | 2449 | 2 => .sh, |
| | 2450 | 4 => .sw, |
| | 2451 | 8 => .sd, |
| | 2452 | else => unreachable, |
| | 2453 | }; |
| | 2454 | |
| | 2455 | _ = try self.addInst(.{ |
| | 2456 | .tag = tag, |
| | 2457 | .data = .{ .i_type = .{ |
| | 2458 | .rd = reg, |
| | 2459 | .rs1 = .sp, |
| | 2460 | .imm12 = @intCast(stack_offset), |
| | 2461 | } }, |
| | 2462 | }); |
| | 2463 | }, |
| | 2464 | else => return self.fail("TODO: genSetStack for size={d}", .{abi_size}), |
| | 2465 | } |
| | 2466 | }, |
| | 2467 | .stack_offset, .load_symbol => { |
| | 2468 | if (abi_size <= 8) { |
| | 2469 | const reg = try self.copyToTmpRegister(ty, mcv); |
| | 2470 | return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); |
| | 2471 | } |
| | 2472 | |
| | 2473 | const ptr_ty = try mod.singleMutPtrType(ty); |
| | 2474 | |
| | 2475 | // TODO call extern memcpy |
| | 2476 | const regs = try self.register_manager.allocRegs(5, .{ null, null, null, null, null }, gp); |
| | 2477 | const regs_locks = self.register_manager.lockRegsAssumeUnused(5, regs); |
| | 2478 | defer for (regs_locks) |reg| { |
| | 2479 | self.register_manager.unlockReg(reg); |
| | 2480 | }; |
| | 2481 | |
| | 2482 | const src_reg = regs[0]; |
| | 2483 | const dst_reg = regs[1]; |
| | 2484 | const len_reg = regs[2]; |
| | 2485 | const count_reg = regs[3]; |
| | 2486 | const tmp_reg = regs[4]; |
| | 2487 | |
| | 2488 | switch (mcv) { |
| | 2489 | .stack_offset => |offset| { |
| | 2490 | if (offset == stack_offset) return; |
| | 2491 | try self.genSetReg(ptr_ty, src_reg, .{ .ptr_stack_offset = offset }); |
| | 2492 | }, |
| | 2493 | .load_symbol => |sym_off| { |
| | 2494 | const atom_index = atom: { |
| | 2495 | const decl_index = mod.funcOwnerDeclIndex(self.func_index); |
| | 2496 | |
| | 2497 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { |
| | 2498 | const atom_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, decl_index); |
| | 2499 | break :atom atom_index; |
| | 2500 | } else return self.fail("TODO genSetStack for {s}", .{@tagName(self.bin_file.tag)}); |
| | 2501 | }; |
| | 2502 | |
| | 2503 | _ = try self.addInst(.{ |
| | 2504 | .tag = .load_symbol, |
| | 2505 | .data = .{ |
| | 2506 | .payload = try self.addExtra(Mir.LoadSymbolPayload{ |
| | 2507 | .register = @intFromEnum(src_reg), |
| | 2508 | .atom_index = atom_index, |
| | 2509 | .sym_index = sym_off.sym, |
| | 2510 | }), |
| | 2511 | }, |
| | 2512 | }); |
| | 2513 | }, |
| | 2514 | else => return self.fail("TODO: genSetStack unreachable {s}", .{@tagName(mcv)}), |
| | 2515 | } |
| | 2516 | |
| | 2517 | try self.genSetReg(ptr_ty, dst_reg, .{ .ptr_stack_offset = stack_offset }); |
| | 2518 | try self.genSetReg(Type.usize, len_reg, .{ .immediate = abi_size }); |
| | 2519 | |
| | 2520 | // memcpy(src, dst, len) |
| | 2521 | try self.genInlineMemcpy(src_reg, dst_reg, len_reg, count_reg, tmp_reg); |
| | 2522 | }, |
| | 2523 | else => return self.fail("TODO: genSetStack {s}", .{@tagName(mcv)}), |
| | 2524 | } |
| | 2525 | } |
| | 2526 | |
| | 2527 | fn genInlineMemcpy( |
| | 2528 | self: *Self, |
| | 2529 | src: Register, |
| | 2530 | dst: Register, |
| | 2531 | len: Register, |
| | 2532 | count: Register, |
| | 2533 | tmp: Register, |
| | 2534 | ) !void { |
| | 2535 | _ = src; |
| | 2536 | _ = dst; |
| | 2537 | _ = len; |
| | 2538 | _ = count; |
| | 2539 | _ = tmp; |
| | 2540 | |
| | 2541 | return self.fail("TODO: genInlineMemcpy", .{}); |
| 2280 | } | 2542 | } |
| 2281 | | 2543 | |
| 2282 | fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void { | 2544 | fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void { |
| | 2545 | const mod = self.bin_file.comp.module.?; |
| | 2546 | const abi_size: u32 = @intCast(ty.abiSize(mod)); |
| | 2547 | |
| 2283 | switch (mcv) { | 2548 | switch (mcv) { |
| 2284 | .dead => unreachable, | 2549 | .dead => unreachable, |
| 2285 | .ptr_stack_offset => unreachable, | 2550 | .ptr_stack_offset => return self.fail("TODO genSetReg ptr_stack_offset", .{}), |
| 2286 | .unreach, .none => return, // Nothing to do. | 2551 | .unreach, .none => return, // Nothing to do. |
| 2287 | .undef => { | 2552 | .undef => { |
| 2288 | if (!self.wantSafety()) | 2553 | if (!self.wantSafety()) |
| ... | @@ -2343,8 +2608,6 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -2343,8 +2608,6 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 2343 | }); | 2608 | }); |
| 2344 | }, | 2609 | }, |
| 2345 | .memory => |addr| { | 2610 | .memory => |addr| { |
| 2346 | // The value is in memory at a hard-coded address. | | |
| 2347 | // If the type is a pointer, it means the pointer address is at this memory location. | | |
| 2348 | try self.genSetReg(ty, reg, .{ .immediate = addr }); | 2611 | try self.genSetReg(ty, reg, .{ .immediate = addr }); |
| 2349 | | 2612 | |
| 2350 | _ = try self.addInst(.{ | 2613 | _ = try self.addInst(.{ |
| ... | @@ -2355,11 +2618,51 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -2355,11 +2618,51 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 2355 | .imm12 = 0, | 2618 | .imm12 = 0, |
| 2356 | } }, | 2619 | } }, |
| 2357 | }); | 2620 | }); |
| 2358 | // LOAD imm=[i12 offset = 0], rs1 = | | |
| 2359 | | 2621 | |
| 2360 | // return self.fail("TODO implement genSetReg memory for riscv64"); | 2622 | // LOAD imm=[i12 offset = 0], rs1 |
| | 2623 | }, |
| | 2624 | .stack_offset => |off| { |
| | 2625 | const tag: Mir.Inst.Tag = switch (abi_size) { |
| | 2626 | 1 => .lb, |
| | 2627 | 2 => .lh, |
| | 2628 | 4 => .lw, |
| | 2629 | 8 => .ld, |
| | 2630 | else => return self.fail("TODO: genSetReg for size {d}", .{abi_size}), |
| | 2631 | }; |
| | 2632 | |
| | 2633 | _ = try self.addInst(.{ |
| | 2634 | .tag = tag, |
| | 2635 | .data = .{ .i_type = .{ |
| | 2636 | .rd = reg, |
| | 2637 | .rs1 = .sp, |
| | 2638 | .imm12 = @intCast(off), |
| | 2639 | } }, |
| | 2640 | }); |
| | 2641 | }, |
| | 2642 | .load_symbol => |sym_off| { |
| | 2643 | assert(sym_off.off == 0); |
| | 2644 | |
| | 2645 | const decl_index = mod.funcOwnerDeclIndex(self.func_index); |
| | 2646 | |
| | 2647 | const atom_index = switch (self.bin_file.tag) { |
| | 2648 | .elf => blk: { |
| | 2649 | const elf_file = self.bin_file.cast(link.File.Elf).?; |
| | 2650 | const atom_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, decl_index); |
| | 2651 | break :blk atom_index; |
| | 2652 | }, |
| | 2653 | else => return self.fail("TODO genSetReg load_symbol for {s}", .{@tagName(self.bin_file.tag)}), |
| | 2654 | }; |
| | 2655 | _ = try self.addInst(.{ |
| | 2656 | .tag = .load_symbol, |
| | 2657 | .data = .{ |
| | 2658 | .payload = try self.addExtra(Mir.LoadSymbolPayload{ |
| | 2659 | .register = @intFromEnum(reg), |
| | 2660 | .atom_index = atom_index, |
| | 2661 | .sym_index = sym_off.sym, |
| | 2662 | }), |
| | 2663 | }, |
| | 2664 | }); |
| 2361 | }, | 2665 | }, |
| 2362 | else => return self.fail("TODO implement getSetReg for riscv64 {}", .{mcv}), | | |
| 2363 | } | 2666 | } |
| 2364 | } | 2667 | } |
| 2365 | | 2668 | |
| ... | @@ -2579,9 +2882,12 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue { | ... | @@ -2579,9 +2882,12 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue { |
| 2579 | .mcv => |mcv| switch (mcv) { | 2882 | .mcv => |mcv| switch (mcv) { |
| 2580 | .none => .none, | 2883 | .none => .none, |
| 2581 | .undef => .undef, | 2884 | .undef => .undef, |
| 2582 | .load_got, .load_symbol, .load_direct, .load_tlv => unreachable, // TODO | 2885 | .load_symbol => |sym_index| .{ .load_symbol = .{ .sym = sym_index } }, |
| 2583 | .immediate => |imm| .{ .immediate = imm }, | 2886 | .immediate => |imm| .{ .immediate = imm }, |
| 2584 | .memory => |addr| .{ .memory = addr }, | 2887 | .memory => |addr| .{ .memory = addr }, |
| | 2888 | .load_got, .load_direct, .load_tlv => { |
| | 2889 | return self.fail("TODO: genTypedValue {s}", .{@tagName(mcv)}); |
| | 2890 | }, |
| 2585 | }, | 2891 | }, |
| 2586 | .fail => |msg| { | 2892 | .fail => |msg| { |
| 2587 | self.err_msg = msg; | 2893 | self.err_msg = msg; |
| ... | @@ -2634,41 +2940,17 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { | ... | @@ -2634,41 +2940,17 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 2634 | // TODO make this generic with other ABIs, in particular | 2940 | // TODO make this generic with other ABIs, in particular |
| 2635 | // with different hardware floating-point calling | 2941 | // with different hardware floating-point calling |
| 2636 | // conventions | 2942 | // conventions |
| 2637 | var next_register: usize = 0; | 2943 | var stack_offset: u32 = 0; |
| 2638 | var next_stack_offset: u32 = 0; | | |
| 2639 | // TODO: this is never assigned, which is a bug, but I don't know how this code works | | |
| 2640 | // well enough to try and fix it. I *think* `next_register += next_stack_offset` is | | |
| 2641 | // supposed to be `next_stack_offset += param_size` in every case where it appears. | | |
| 2642 | _ = &next_stack_offset; | | |
| 2643 | | | |
| 2644 | const argument_registers = [_]Register{ .a0, .a1, .a2, .a3, .a4, .a5, .a6, .a7 }; | | |
| 2645 | | 2944 | |
| 2646 | for (fn_info.param_types.get(ip), result.args) |ty, *result_arg| { | 2945 | for (fn_info.param_types.get(ip), result.args) |ty, *result_arg| { |
| 2647 | const param_size: u32 = @intCast(Type.fromInterned(ty).abiSize(mod)); | 2946 | const param_type = Type.fromInterned(ty); |
| 2648 | if (param_size <= 8) { | 2947 | const param_size: u32 = @intCast(param_type.abiSize(mod)); |
| 2649 | if (next_register < argument_registers.len) { | 2948 | |
| 2650 | result_arg.* = .{ .register = argument_registers[next_register] }; | 2949 | result_arg.* = .{ .stack_offset = stack_offset }; |
| 2651 | next_register += 1; | 2950 | stack_offset += param_size; |
| 2652 | } else { | | |
| 2653 | result_arg.* = .{ .stack_offset = next_stack_offset }; | | |
| 2654 | next_register += next_stack_offset; | | |
| 2655 | } | | |
| 2656 | } else if (param_size <= 16) { | | |
| 2657 | if (next_register < argument_registers.len - 1) { | | |
| 2658 | return self.fail("TODO MCValues with 2 registers", .{}); | | |
| 2659 | } else if (next_register < argument_registers.len) { | | |
| 2660 | return self.fail("TODO MCValues split register + stack", .{}); | | |
| 2661 | } else { | | |
| 2662 | result_arg.* = .{ .stack_offset = next_stack_offset }; | | |
| 2663 | next_register += next_stack_offset; | | |
| 2664 | } | | |
| 2665 | } else { | | |
| 2666 | result_arg.* = .{ .stack_offset = next_stack_offset }; | | |
| 2667 | next_register += next_stack_offset; | | |
| 2668 | } | | |
| 2669 | } | 2951 | } |
| 2670 | | 2952 | |
| 2671 | result.stack_byte_count = next_stack_offset; | 2953 | result.stack_byte_count = stack_offset; |
| 2672 | result.stack_align = .@"16"; | 2954 | result.stack_align = .@"16"; |
| 2673 | }, | 2955 | }, |
| 2674 | else => return self.fail("TODO implement function parameters for {} on riscv64", .{cc}), | 2956 | else => return self.fail("TODO implement function parameters for {} on riscv64", .{cc}), |