authorgravatar for david@vortan.devDavid Rubin <david@vortan.dev> 2024-03-10 19:06:37-07:00
committergravatar for david@vortan.devDavid Rubin <david@vortan.dev> 2024-05-11 02:17:11-07:00
logdceff2592f6a6305770916499c688071563ddf0d
tree421186eb8d27e095891ee211099eda57052dda20
parent1550b5b16d4899cb4f7184ee3d392b4a6197ed42

riscv: initial cleanup and work


4 files changed, 784 insertions(+), 262 deletions(-)

lib/std/builtin.zig+7-1
...@@ -759,6 +759,13 @@ else...@@ -759,6 +759,13 @@ else
759pub fn default_panic(msg: []const u8, error_return_trace: ?*StackTrace, ret_addr: ?usize) noreturn {759pub fn default_panic(msg: []const u8, error_return_trace: ?*StackTrace, ret_addr: ?usize) noreturn {
760 @setCold(true);760 @setCold(true);
761761
762 // stage2_riscv64 backend doesn't support loops yet.
763 if (builtin.zig_backend == .stage2_riscv64 or
764 builtin.cpu.arch == .riscv64)
765 {
766 unreachable;
767 }
768
762 // For backends that cannot handle the language features depended on by the769 // For backends that cannot handle the language features depended on by the
763 // default panic handler, we have a simpler panic handler:770 // default panic handler, we have a simpler panic handler:
764 if (builtin.zig_backend == .stage2_wasm or771 if (builtin.zig_backend == .stage2_wasm or
...@@ -766,7 +773,6 @@ pub fn default_panic(msg: []const u8, error_return_trace: ?*StackTrace, ret_addr...@@ -766,7 +773,6 @@ pub fn default_panic(msg: []const u8, error_return_trace: ?*StackTrace, ret_addr
766 builtin.zig_backend == .stage2_aarch64 or773 builtin.zig_backend == .stage2_aarch64 or
767 builtin.zig_backend == .stage2_x86 or774 builtin.zig_backend == .stage2_x86 or
768 (builtin.zig_backend == .stage2_x86_64 and (builtin.target.ofmt != .elf and builtin.target.ofmt != .macho)) or775 (builtin.zig_backend == .stage2_x86_64 and (builtin.target.ofmt != .elf and builtin.target.ofmt != .macho)) or
769 builtin.zig_backend == .stage2_riscv64 or
770 builtin.zig_backend == .stage2_sparc64 or776 builtin.zig_backend == .stage2_sparc64 or
771 builtin.zig_backend == .stage2_spirv64)777 builtin.zig_backend == .stage2_spirv64)
772 {778 {
src/arch/riscv64/CodeGen.zig+508-226
...@@ -33,7 +33,6 @@ const abi = @import("abi.zig");...@@ -33,7 +33,6 @@ const abi = @import("abi.zig");
33const Register = bits.Register;33const Register = bits.Register;
34const RegisterManager = abi.RegisterManager;34const RegisterManager = abi.RegisterManager;
35const RegisterLock = RegisterManager.RegisterLock;35const RegisterLock = RegisterManager.RegisterLock;
36const Instruction = abi.Instruction;
37const callee_preserved_regs = abi.callee_preserved_regs;36const callee_preserved_regs = abi.callee_preserved_regs;
38const gp = abi.RegisterClass.gp;37const gp = abi.RegisterClass.gp;
3938
...@@ -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,
9695
97const air_bookkeeping_init = if (std.debug.runtime_safety) @as(usize, 0) else {};96const air_bookkeeping_init = if (std.debug.runtime_safety) @as(usize, 0) else {};
9897
98const SymbolOffset = struct { sym: u32, off: i32 = 0 };
99
99const MCValue = union(enum) {100const 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 use102 /// 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,
149154
150 .register,155 .register,
...@@ -165,12 +170,12 @@ const Branch = struct {...@@ -165,12 +170,12 @@ const Branch = struct {
165170
166const StackAllocation = struct {171const 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};
171176
172const BlockData = struct {177const BlockData = struct {
173 relocs: std.ArrayListUnmanaged(Reloc),178 relocs: std.ArrayListUnmanaged(Mir.Inst.Index),
174 /// The first break instruction encounters `null` here and chooses a179 /// 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 for181 /// 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};
180185
181const 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
193const BigTomb = struct {186const 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);
276270
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}
330324
325fn addNop(self: *Self) error{OutOfMemory}!Mir.Inst.Index {
326 return try self.addInst(.{
327 .tag = .nop,
328 .data = .{ .nop = {} },
329 });
330}
331
331pub fn addExtra(self: *Self, extra: anytype) Allocator.Error!u32 {332pub 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 {
350fn gen(self: *Self) !void {351fn 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 });
366354
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 });
386356
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 }
414361
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 });
424366
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 });
434368
435 // addi sp, sp, 16369 // 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 });
444373
445 // ret374 _ = 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 });
455378
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 }
457389
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 }
463394
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 {
535466
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),
537468
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),
544475
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", .{}),
621553
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", .{}),
624556
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),
630560
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 };
1034969
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 lowering987/// looks at the lhs and rhs and determines which kind of lowering
1053/// would be best suitable and then delegates the lowering to other988/// 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.
1055fn binOp(992fn 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 floats1003 // 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}
11811124
1182fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void {1125fn 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}
11861140
1187fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void {1141fn 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 {
13521306
1353fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void {1307fn 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}
13581315
1316fn 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
1359fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {1330fn 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}
13641335
...@@ -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
1500fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!void {1471fn 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}
15251499
...@@ -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 {
1553fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type) !void {1527fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type) !void {
1554 _ = ptr_ty;1528 _ = ptr_ty;
15551529
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}
15781557
...@@ -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 {
1596fn airStructFieldPtr(self: *Self, inst: Air.Inst.Index) !void {1575fn 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}
16011581
1602fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u8) !void {1582fn 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}
1606fn structFieldPtr(self: *Self, operand: Air.Inst.Ref, ty: Air.Inst.Ref, index: u32) !void {1587
1588fn 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}
16131596
1614fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {1597fn 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}
16211605
1622fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void {1606fn 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 }
17431728
...@@ -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}
18321817
1833fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {1818fn 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 {
18421828
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;
18481833
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}
18521838
1853fn airCmpVector(self: *Self, inst: Air.Inst.Index) !void {1839fn 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}
18791865
1880fn airDbgInlineBlock(self: *Self, inst: Air.Inst.Index) !void {1866fn 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 change1870 // 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}
18891873
1890fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {1874fn 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}
18981882
1899fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {1883fn 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 }
19012016
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
2025fn 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}
19052044
1906fn isNull(self: *Self, operand: MCValue) !MCValue {2045fn 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}
20522194
2053/// Send control flow to the `index` of `self.code`.2195/// Send control flow to the `index` of `self.code`.
2054fn jump(self: *Self, index: usize) !void {2196fn 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}
20582204
2059fn airBlock(self: *Self, inst: Air.Inst.Index) !void {2205fn 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
2065fn 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 block2221 // TODO emit debug info lexical block
2078 try self.genBody(body);2222 try self.genBody(body);
20792223
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 }
20812227
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}
20932239
2094fn performReloc(self: *Self, reloc: Reloc) !void {2240fn 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}
21012248
...@@ -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);
21372284
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}
21402295
2141fn airAsm(self: *Self, inst: Air.Inst.Index) !void {2296fn 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
22612416
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.
2263fn setRegOrMem(self: *Self, ty: Type, loc: MCValue, val: MCValue) !void {2418fn 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}
22742430
2275fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerError!void {2431fn 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
2527fn 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}
22812543
2282fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void {2544fn 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 });
23492612
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 =
23592621
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}
23652668
...@@ -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, // TODO2885 .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 particular2940 // TODO make this generic with other ABIs, in particular
2635 // with different hardware floating-point calling2941 // with different hardware floating-point calling
2636 // conventions2942 // 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 };
26452944
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 }
26702952
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}),
src/arch/riscv64/Emit.zig+173-20
...@@ -27,6 +27,8 @@ prev_di_column: u32,...@@ -27,6 +27,8 @@ prev_di_column: u32,
27/// Relative to the beginning of `code`.27/// Relative to the beginning of `code`.
28prev_di_pc: usize,28prev_di_pc: usize,
2929
30const log = std.log.scoped(.emit);
31
30const InnerError = error{32const InnerError = error{
31 OutOfMemory,33 OutOfMemory,
32 EmitFail,34 EmitFail,
...@@ -37,33 +39,57 @@ pub fn emitMir(...@@ -37,33 +39,57 @@ pub fn emitMir(
37) InnerError!void {39) InnerError!void {
38 const mir_tags = emit.mir.instructions.items(.tag);40 const mir_tags = emit.mir.instructions.items(.tag);
3941
42 // TODO: compute branch offsets
43 // try emit.lowerMir();
44
40 // Emit machine code45 // Emit machine code
41 for (mir_tags, 0..) |tag, index| {46 for (mir_tags, 0..) |tag, index| {
42 const inst = @as(u32, @intCast(index));47 const inst = @as(u32, @intCast(index));
48 log.debug("emitMir: {s}", .{@tagName(tag)});
43 switch (tag) {49 switch (tag) {
44 .add => try emit.mirRType(inst),50 .add => try emit.mirRType(inst),
45 .sub => try emit.mirRType(inst),51 .sub => try emit.mirRType(inst),
4652
53 .cmp_eq => try emit.mirRType(inst),
54 .cmp_gt => try emit.mirRType(inst),
55
56 .beq => try emit.mirBType(inst),
57 .bne => try emit.mirBType(inst),
58
47 .addi => try emit.mirIType(inst),59 .addi => try emit.mirIType(inst),
48 .jalr => try emit.mirIType(inst),60 .jalr => try emit.mirIType(inst),
49 .ld => try emit.mirIType(inst),61
50 .sd => try emit.mirIType(inst),62 .jal => try emit.mirJType(inst),
5163
52 .ebreak => try emit.mirSystem(inst),64 .ebreak => try emit.mirSystem(inst),
53 .ecall => try emit.mirSystem(inst),65 .ecall => try emit.mirSystem(inst),
54 .unimp => try emit.mirSystem(inst),66 .unimp => try emit.mirSystem(inst),
5567
56 .dbg_line => try emit.mirDbgLine(inst),68 .dbg_line => try emit.mirDbgLine(inst),
57
58 .dbg_prologue_end => try emit.mirDebugPrologueEnd(),69 .dbg_prologue_end => try emit.mirDebugPrologueEnd(),
59 .dbg_epilogue_begin => try emit.mirDebugEpilogueBegin(),70 .dbg_epilogue_begin => try emit.mirDebugEpilogueBegin(),
6071
72 .psuedo_prologue => try emit.mirPsuedo(inst),
73 .psuedo_jump => try emit.mirPsuedo(inst),
74
61 .mv => try emit.mirRR(inst),75 .mv => try emit.mirRR(inst),
6276
63 .nop => try emit.mirNop(inst),77 .nop => try emit.mirNop(inst),
64 .ret => try emit.mirNop(inst),78 .ret => try emit.mirNop(inst),
6579
66 .lui => try emit.mirUType(inst),80 .lui => try emit.mirUType(inst),
81
82 .ld => try emit.mirIType(inst),
83 .sd => try emit.mirIType(inst),
84 .lw => try emit.mirIType(inst),
85 .sw => try emit.mirIType(inst),
86 .lh => try emit.mirIType(inst),
87 .sh => try emit.mirIType(inst),
88 .lb => try emit.mirIType(inst),
89 .sb => try emit.mirIType(inst),
90 .ldr_ptr_stack => try emit.mirIType(inst),
91
92 .load_symbol => try emit.mirLoadSymbol(inst),
67 }93 }
68 }94 }
69}95}
...@@ -86,15 +112,19 @@ fn fail(emit: *Emit, comptime format: []const u8, args: anytype) InnerError {...@@ -86,15 +112,19 @@ fn fail(emit: *Emit, comptime format: []const u8, args: anytype) InnerError {
86 return error.EmitFail;112 return error.EmitFail;
87}113}
88114
89fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void {115fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) !void {
90 const delta_line = @as(i32, @intCast(line)) - @as(i32, @intCast(self.prev_di_line));116 log.debug("Line: {} {}\n", .{ line, emit.prev_di_line });
91 const delta_pc: usize = self.code.items.len - self.prev_di_pc;117 const delta_line = @as(i32, @intCast(line)) - @as(i32, @intCast(emit.prev_di_line));
92 switch (self.debug_output) {118 const delta_pc: usize = emit.code.items.len - emit.prev_di_pc;
119 log.debug("(advance pc={d} and line={d})", .{ delta_pc, delta_line });
120 switch (emit.debug_output) {
93 .dwarf => |dw| {121 .dwarf => |dw| {
122 if (column != emit.prev_di_column) try dw.setColumn(column);
123 if (delta_line == 0) return; // TODO: remove this
94 try dw.advancePCAndLine(delta_line, delta_pc);124 try dw.advancePCAndLine(delta_line, delta_pc);
95 self.prev_di_line = line;125 emit.prev_di_line = line;
96 self.prev_di_column = column;126 emit.prev_di_column = column;
97 self.prev_di_pc = self.code.items.len;127 emit.prev_di_pc = emit.code.items.len;
98 },128 },
99 .plan9 => |dbg_out| {129 .plan9 => |dbg_out| {
100 if (delta_pc <= 0) return; // only do this when the pc changes130 if (delta_pc <= 0) return; // only do this when the pc changes
...@@ -113,12 +143,12 @@ fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void {...@@ -113,12 +143,12 @@ fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void {
113 // we don't need to do anything, because adding the pc quanta does it for us143 // we don't need to do anything, because adding the pc quanta does it for us
114 } else unreachable;144 } else unreachable;
115 if (dbg_out.start_line == null)145 if (dbg_out.start_line == null)
116 dbg_out.start_line = self.prev_di_line;146 dbg_out.start_line = emit.prev_di_line;
117 dbg_out.end_line = line;147 dbg_out.end_line = line;
118 // only do this if the pc changed148 // only do this if the pc changed
119 self.prev_di_line = line;149 emit.prev_di_line = line;
120 self.prev_di_column = column;150 emit.prev_di_column = column;
121 self.prev_di_pc = self.code.items.len;151 emit.prev_di_pc = emit.code.items.len;
122 },152 },
123 .none => {},153 .none => {},
124 }154 }
...@@ -131,6 +161,19 @@ fn mirRType(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -131,6 +161,19 @@ fn mirRType(emit: *Emit, inst: Mir.Inst.Index) !void {
131 switch (tag) {161 switch (tag) {
132 .add => try emit.writeInstruction(Instruction.add(r_type.rd, r_type.rs1, r_type.rs2)),162 .add => try emit.writeInstruction(Instruction.add(r_type.rd, r_type.rs1, r_type.rs2)),
133 .sub => try emit.writeInstruction(Instruction.sub(r_type.rd, r_type.rs1, r_type.rs2)),163 .sub => try emit.writeInstruction(Instruction.sub(r_type.rd, r_type.rs1, r_type.rs2)),
164 .cmp_eq => try emit.writeInstruction(Instruction.slt(r_type.rd, r_type.rs1, r_type.rs2)),
165 else => unreachable,
166 }
167}
168
169fn mirBType(emit: *Emit, inst: Mir.Inst.Index) !void {
170 const tag = emit.mir.instructions.items(.tag)[inst];
171 const b_type = emit.mir.instructions.items(.data)[inst].b_type;
172
173 // const inst = b_type.imm12;
174
175 switch (tag) {
176 .beq => try emit.writeInstruction(Instruction.beq(b_type.rs1, b_type.rs2, b_type.imm12)),
134 else => unreachable,177 else => unreachable,
135 }178 }
136}179}
...@@ -142,8 +185,30 @@ fn mirIType(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -142,8 +185,30 @@ fn mirIType(emit: *Emit, inst: Mir.Inst.Index) !void {
142 switch (tag) {185 switch (tag) {
143 .addi => try emit.writeInstruction(Instruction.addi(i_type.rd, i_type.rs1, i_type.imm12)),186 .addi => try emit.writeInstruction(Instruction.addi(i_type.rd, i_type.rs1, i_type.imm12)),
144 .jalr => try emit.writeInstruction(Instruction.jalr(i_type.rd, i_type.imm12, i_type.rs1)),187 .jalr => try emit.writeInstruction(Instruction.jalr(i_type.rd, i_type.imm12, i_type.rs1)),
188
145 .ld => try emit.writeInstruction(Instruction.ld(i_type.rd, i_type.imm12, i_type.rs1)),189 .ld => try emit.writeInstruction(Instruction.ld(i_type.rd, i_type.imm12, i_type.rs1)),
146 .sd => try emit.writeInstruction(Instruction.sd(i_type.rd, i_type.imm12, i_type.rs1)),190 .sd => try emit.writeInstruction(Instruction.sd(i_type.rd, i_type.imm12, i_type.rs1)),
191 .lw => try emit.writeInstruction(Instruction.lw(i_type.rd, i_type.imm12, i_type.rs1)),
192 .sw => try emit.writeInstruction(Instruction.sw(i_type.rd, i_type.imm12, i_type.rs1)),
193 .lh => try emit.writeInstruction(Instruction.lh(i_type.rd, i_type.imm12, i_type.rs1)),
194 .sh => try emit.writeInstruction(Instruction.sh(i_type.rd, i_type.imm12, i_type.rs1)),
195 .lb => try emit.writeInstruction(Instruction.lb(i_type.rd, i_type.imm12, i_type.rs1)),
196 .sb => try emit.writeInstruction(Instruction.sb(i_type.rd, i_type.imm12, i_type.rs1)),
197
198 .ldr_ptr_stack => try emit.writeInstruction(Instruction.add(i_type.rd, i_type.rs1, .sp)),
199
200 else => unreachable,
201 }
202}
203
204fn mirJType(emit: *Emit, inst: Mir.Inst.Index) !void {
205 const tag = emit.mir.instructions.items(.tag)[inst];
206 const j_type = emit.mir.instructions.items(.data)[inst].j_type;
207
208 switch (tag) {
209 .jal => {
210 try emit.writeInstruction(Instruction.jal(j_type.rd, j_type.imm21));
211 },
147 else => unreachable,212 else => unreachable,
148 }213 }
149}214}
...@@ -169,28 +234,55 @@ fn mirDbgLine(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -169,28 +234,55 @@ fn mirDbgLine(emit: *Emit, inst: Mir.Inst.Index) !void {
169 }234 }
170}235}
171236
172fn mirDebugPrologueEnd(self: *Emit) !void {237fn mirDebugPrologueEnd(emit: *Emit) !void {
173 switch (self.debug_output) {238 switch (emit.debug_output) {
174 .dwarf => |dw| {239 .dwarf => |dw| {
175 try dw.setPrologueEnd();240 try dw.setPrologueEnd();
176 try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column);241 try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);
177 },242 },
178 .plan9 => {},243 .plan9 => {},
179 .none => {},244 .none => {},
180 }245 }
181}246}
182247
183fn mirDebugEpilogueBegin(self: *Emit) !void {248fn mirDebugEpilogueBegin(emit: *Emit) !void {
184 switch (self.debug_output) {249 switch (emit.debug_output) {
185 .dwarf => |dw| {250 .dwarf => |dw| {
186 try dw.setEpilogueBegin();251 try dw.setEpilogueBegin();
187 try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column);252 try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);
188 },253 },
189 .plan9 => {},254 .plan9 => {},
190 .none => {},255 .none => {},
191 }256 }
192}257}
193258
259fn mirPsuedo(emit: *Emit, inst: Mir.Inst.Index) !void {
260 const tag = emit.mir.instructions.items(.tag)[inst];
261 const data = emit.mir.instructions.items(.data)[inst];
262
263 switch (tag) {
264 .psuedo_prologue => {
265 const imm12 = data.imm12;
266 const stack_size: i12 = @max(32, imm12);
267
268 try emit.writeInstruction(Instruction.addi(.sp, .sp, -stack_size));
269 try emit.writeInstruction(Instruction.sd(.ra, stack_size - 8, .sp));
270 try emit.writeInstruction(Instruction.sd(.s0, stack_size - 16, .sp));
271 try emit.writeInstruction(Instruction.addi(.s0, .sp, stack_size));
272 },
273
274 .psuedo_jump => {
275 const target = data.inst;
276 const offset: i12 = @intCast(emit.code.items.len);
277 _ = target;
278
279 try emit.writeInstruction(Instruction.jal(.s0, offset));
280 },
281
282 else => unreachable,
283 }
284}
285
194fn mirRR(emit: *Emit, inst: Mir.Inst.Index) !void {286fn mirRR(emit: *Emit, inst: Mir.Inst.Index) !void {
195 const tag = emit.mir.instructions.items(.tag)[inst];287 const tag = emit.mir.instructions.items(.tag)[inst];
196 const rr = emit.mir.instructions.items(.data)[inst].rr;288 const rr = emit.mir.instructions.items(.data)[inst].rr;
...@@ -200,6 +292,7 @@ fn mirRR(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -200,6 +292,7 @@ fn mirRR(emit: *Emit, inst: Mir.Inst.Index) !void {
200 else => unreachable,292 else => unreachable,
201 }293 }
202}294}
295
203fn mirUType(emit: *Emit, inst: Mir.Inst.Index) !void {296fn mirUType(emit: *Emit, inst: Mir.Inst.Index) !void {
204 const tag = emit.mir.instructions.items(.tag)[inst];297 const tag = emit.mir.instructions.items(.tag)[inst];
205 const u_type = emit.mir.instructions.items(.data)[inst].u_type;298 const u_type = emit.mir.instructions.items(.data)[inst].u_type;
...@@ -219,3 +312,63 @@ fn mirNop(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -219,3 +312,63 @@ fn mirNop(emit: *Emit, inst: Mir.Inst.Index) !void {
219 else => unreachable,312 else => unreachable,
220 }313 }
221}314}
315
316fn mirLoadSymbol(emit: *Emit, inst: Mir.Inst.Index) !void {
317 // const tag = emit.mir.instructions.items(.tag)[inst];
318 const payload = emit.mir.instructions.items(.data)[inst].payload;
319 const data = emit.mir.extraData(Mir.LoadSymbolPayload, payload).data;
320 const reg = @as(Register, @enumFromInt(data.register));
321
322 const end_offset = @as(u32, @intCast(emit.code.items.len));
323 try emit.writeInstruction(Instruction.lui(reg, 0));
324 try emit.writeInstruction(Instruction.lw(reg, 0, reg));
325
326 switch (emit.bin_file.tag) {
327 .elf => {
328 const elf_file = emit.bin_file.cast(link.File.Elf).?;
329 const atom_ptr = elf_file.symbol(data.atom_index).atom(elf_file).?;
330
331 const hi_r_type = @intFromEnum(std.elf.R_RISCV.HI20);
332
333 try atom_ptr.addReloc(elf_file, .{
334 .r_offset = end_offset,
335 .r_info = (@as(u64, @intCast(data.sym_index)) << 32) | hi_r_type,
336 .r_addend = 0,
337 });
338
339 const lo_r_type = @intFromEnum(std.elf.R_RISCV.LO12_I);
340
341 try atom_ptr.addReloc(elf_file, .{
342 .r_offset = end_offset + 4,
343 .r_info = (@as(u64, @intCast(data.sym_index)) << 32) | lo_r_type,
344 .r_addend = 0,
345 });
346 },
347 else => unreachable,
348 }
349}
350
351fn isBranch(tag: Mir.Inst.Tag) bool {
352 switch (tag) {
353 .psuedo_jump => true,
354 else => false,
355 }
356}
357
358fn lowerMir(emit: *Emit) !void {
359 const comp = emit.bin_file.comp;
360 const gpa = comp.gpa;
361 const mir_tags = emit.mir.instructions.items(.tag);
362
363 _ = gpa;
364
365 for (mir_tags, 0..) |tag, index| {
366 const inst: u32 = @intCast(index);
367
368 if (isBranch(tag)) {
369 const target_inst = emit.mir.instructions.items(.data)[inst].inst;
370
371 _ = target_inst;
372 }
373 }
374}
src/arch/riscv64/Mir.zig+96-15
...@@ -24,25 +24,72 @@ pub const Inst = struct {...@@ -24,25 +24,72 @@ pub const Inst = struct {
24 data: Data,24 data: Data,
2525
26 pub const Tag = enum(u16) {26 pub const Tag = enum(u16) {
27 add,
28 addi,27 addi,
29 /// Pseudo-instruction: End of prologue
30 dbg_prologue_end,
31 /// Pseudo-instruction: Beginning of epilogue
32 dbg_epilogue_begin,
33 /// Pseudo-instruction: Update debug line
34 dbg_line,
35 unimp,
36 ebreak,
37 ecall,
38 jalr,28 jalr,
39 ld,
40 lui,29 lui,
41 mv,30 mv,
31
32 unimp,
33 ebreak,
34 ecall,
35
36 /// Addition
37 add,
38 /// Subtraction
39 sub,
40
41 jal,
42
43 // TODO: Maybe create a special data for compares that includes the ops
44 /// Compare equal, uses r_type
45 cmp_eq,
46 /// Compare greater than, uses r_type
47 cmp_gt,
48
49 /// Branch if equal Uses b_type
50 beq,
51 /// Branch if not eql Uses b_type
52 bne,
53
42 nop,54 nop,
43 ret,55 ret,
56
57 /// Load double (64 bits)
58 ld,
59 /// Store double (64 bits)
44 sd,60 sd,
45 sub,61 /// Load word (32 bits)
62 lw,
63 /// Store word (32 bits)
64 sw,
65 /// Load half (16 bits)
66 lh,
67 /// Store half (16 bits)
68 sh,
69 /// Load byte (8 bits)
70 lb,
71 /// Store byte (8 bits)
72 sb,
73
74 /// Pseudo-instruction: End of prologue
75 dbg_prologue_end,
76 /// Pseudo-instruction: Beginning of epilogue
77 dbg_epilogue_begin,
78 /// Pseudo-instruction: Update debug line
79 dbg_line,
80
81 /// Psuedo-instruction that will generate a backpatched
82 /// function prologue.
83 psuedo_prologue,
84 /// Jumps. Uses `inst` payload.
85 psuedo_jump,
86
87 // TODO: add description
88 load_symbol,
89
90 // TODO: add description
91 // this is bad, remove this
92 ldr_ptr_stack,
46 };93 };
4794
48 /// The position of an MIR instruction within the `Mir` instructions array.95 /// The position of an MIR instruction within the `Mir` instructions array.
...@@ -63,7 +110,11 @@ pub const Inst = struct {...@@ -63,7 +110,11 @@ pub const Inst = struct {
63 /// A 16-bit immediate value.110 /// A 16-bit immediate value.
64 ///111 ///
65 /// Used by e.g. svc112 /// Used by e.g. svc
66 imm16: u16,113 imm16: i16,
114 /// A 12-bit immediate value.
115 ///
116 /// Used by e.g. psuedo_prologue
117 imm12: i12,
67 /// Index into `extra`. Meaning of what can be found there is context-dependent.118 /// Index into `extra`. Meaning of what can be found there is context-dependent.
68 ///119 ///
69 /// Used by e.g. load_memory120 /// Used by e.g. load_memory
...@@ -95,6 +146,21 @@ pub const Inst = struct {...@@ -95,6 +146,21 @@ pub const Inst = struct {
95 rs1: Register,146 rs1: Register,
96 rs2: Register,147 rs2: Register,
97 },148 },
149 /// B-Type
150 ///
151 /// Used by e.g. beq
152 b_type: struct {
153 rs1: Register,
154 rs2: Register,
155 imm12: i13,
156 },
157 /// J-Type
158 ///
159 /// Used by e.g. jal
160 j_type: struct {
161 rd: Register,
162 imm21: i21,
163 },
98 /// U-Type164 /// U-Type
99 ///165 ///
100 /// Used by e.g. lui166 /// Used by e.g. lui
...@@ -111,10 +177,19 @@ pub const Inst = struct {...@@ -111,10 +177,19 @@ pub const Inst = struct {
111 },177 },
112 };178 };
113179
180 const CompareOp = enum {
181 eq,
182 neq,
183 gt,
184 gte,
185 lt,
186 lte,
187 };
188
114 // Make sure we don't accidentally make instructions bigger than expected.189 // Make sure we don't accidentally make instructions bigger than expected.
115 // Note that in safety builds, Zig is allowed to insert a secret field for safety checks.190 // Note that in Debug builds, Zig is allowed to insert a secret field for safety checks.
116 // comptime {191 // comptime {
117 // if (!std.debug.runtime_safety) {192 // if (builtin.mode != .Debug) {
118 // assert(@sizeOf(Inst) == 8);193 // assert(@sizeOf(Inst) == 8);
119 // }194 // }
120 // }195 // }
...@@ -145,3 +220,9 @@ pub fn extraData(mir: Mir, comptime T: type, index: usize) struct { data: T, end...@@ -145,3 +220,9 @@ pub fn extraData(mir: Mir, comptime T: type, index: usize) struct { data: T, end
145 .end = i,220 .end = i,
146 };221 };
147}222}
223
224pub const LoadSymbolPayload = struct {
225 register: u32,
226 atom_index: u32,
227 sym_index: u32,
228};