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
759759pub fn default_panic(msg: []const u8, error_return_trace: ?*StackTrace, ret_addr: ?usize) noreturn {
760760 @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
762769 // For backends that cannot handle the language features depended on by the
763770 // default panic handler, we have a simpler panic handler:
764771 if (builtin.zig_backend == .stage2_wasm or
......@@ -766,7 +773,6 @@ pub fn default_panic(msg: []const u8, error_return_trace: ?*StackTrace, ret_addr
766773 builtin.zig_backend == .stage2_aarch64 or
767774 builtin.zig_backend == .stage2_x86 or
768775 (builtin.zig_backend == .stage2_x86_64 and (builtin.target.ofmt != .elf and builtin.target.ofmt != .macho)) or
769 builtin.zig_backend == .stage2_riscv64 or
770776 builtin.zig_backend == .stage2_sparc64 or
771777 builtin.zig_backend == .stage2_spirv64)
772778 {
src/arch/riscv64/CodeGen.zig+508-226
......@@ -33,7 +33,6 @@ const abi = @import("abi.zig");
3333const Register = bits.Register;
3434const RegisterManager = abi.RegisterManager;
3535const RegisterLock = RegisterManager.RegisterLock;
36const Instruction = abi.Instruction;
3736const callee_preserved_regs = abi.callee_preserved_regs;
3837const gp = abi.RegisterClass.gp;
3938
......@@ -96,6 +95,8 @@ air_bookkeeping: @TypeOf(air_bookkeeping_init) = air_bookkeeping_init,
9695
9796const air_bookkeeping_init = if (std.debug.runtime_safety) @as(usize, 0) else {};
9897
98const SymbolOffset = struct { sym: u32, off: i32 = 0 };
99
99100const MCValue = union(enum) {
100101 /// No runtime bits. `void` types, empty structs, u0, enums with 1 tag, etc.
101102 /// TODO Look into deleting this tag and using `dead` instead, since every use
......@@ -110,6 +111,9 @@ const MCValue = union(enum) {
110111 /// A pointer-sized integer that fits in a register.
111112 /// If the type is a pointer, this is the pointer address in virtual address space.
112113 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,
113117 /// The value is in a target-specific register.
114118 register: Register,
115119 /// The value is in memory at a hard-coded address.
......@@ -145,6 +149,7 @@ const MCValue = union(enum) {
145149 .memory,
146150 .ptr_stack_offset,
147151 .undef,
152 .load_symbol,
148153 => false,
149154
150155 .register,
......@@ -165,12 +170,12 @@ const Branch = struct {
165170
166171const StackAllocation = struct {
167172 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
169174 size: u32,
170175};
171176
172177const BlockData = struct {
173 relocs: std.ArrayListUnmanaged(Reloc),
178 relocs: std.ArrayListUnmanaged(Mir.Inst.Index),
174179 /// The first break instruction encounters `null` here and chooses a
175180 /// machine code value for the block result, populating this field.
176181 /// Following break instructions encounter that value and use it for
......@@ -178,18 +183,6 @@ const BlockData = struct {
178183 mcv: MCValue,
179184};
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
193186const BigTomb = struct {
194187 function: *Self,
195188 inst: Air.Inst.Index,
......@@ -272,6 +265,7 @@ pub fn generate(
272265 },
273266 else => |e| return e,
274267 };
268
275269 defer call_info.deinit(&function);
276270
277271 function.args = call_info.args;
......@@ -328,6 +322,13 @@ fn addInst(self: *Self, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index {
328322 return result_index;
329323}
330324
325fn addNop(self: *Self) error{OutOfMemory}!Mir.Inst.Index {
326 return try self.addInst(.{
327 .tag = .nop,
328 .data = .{ .nop = {} },
329 });
330}
331
331332pub fn addExtra(self: *Self, extra: anytype) Allocator.Error!u32 {
332333 const fields = std.meta.fields(@TypeOf(extra));
333334 try self.mir_extra.ensureUnusedCapacity(self.gpa, fields.len);
......@@ -350,115 +351,45 @@ pub fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 {
350351fn gen(self: *Self) !void {
351352 const mod = self.bin_file.comp.module.?;
352353 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)
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 });
355 if (cc == .Naked) return self.fail("TODO: gen support callconv(.{s})", .{@tagName(cc)});
386356
387 _ = try self.addInst(.{
388 .tag = .dbg_prologue_end,
389 .data = .{ .nop = {} },
390 });
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 }
357 _ = try self.addInst(.{
358 .tag = .psuedo_prologue,
359 .data = .{ .imm12 = 0 }, // Backpatched later.
360 });
414361
415 // ld ra, 8(sp)
416 _ = try self.addInst(.{
417 .tag = .ld,
418 .data = .{ .i_type = .{
419 .rd = .ra,
420 .rs1 = .sp,
421 .imm12 = 8,
422 } },
423 });
362 _ = try self.addInst(.{
363 .tag = .dbg_prologue_end,
364 .data = .{ .nop = {} },
365 });
424366
425 // ld s0, 0(sp)
426 _ = try self.addInst(.{
427 .tag = .ld,
428 .data = .{ .i_type = .{
429 .rd = .s0,
430 .rs1 = .sp,
431 .imm12 = 0,
432 } },
433 });
367 try self.genBody(self.air.getMainBody());
434368
435 // addi sp, sp, 16
436 _ = try self.addInst(.{
437 .tag = .addi,
438 .data = .{ .i_type = .{
439 .rd = .sp,
440 .rs1 = .sp,
441 .imm12 = 16,
442 } },
443 });
369 // Backpatch prologue stack size
370 if (math.cast(i12, self.max_end_stack)) |casted_stack_size| {
371 self.mir_instructions.items(.data)[0].imm12 = casted_stack_size;
372 } else return self.fail("TODO support larger stack sizes, got {}", .{self.max_end_stack});
444373
445 // ret
446 _ = try self.addInst(.{
447 .tag = .ret,
448 .data = .{ .nop = {} },
449 });
450 } else {
451 _ = try self.addInst(.{
452 .tag = .dbg_prologue_end,
453 .data = .{ .nop = {} },
454 });
374 _ = try self.addInst(.{
375 .tag = .dbg_epilogue_begin,
376 .data = .{ .nop = {} },
377 });
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(.{
459 .tag = .dbg_epilogue_begin,
460 .data = .{ .nop = {} },
461 });
390 for (self.exitlude_jump_relocs.items) |jmp_reloc| {
391 _ = jmp_reloc;
392 return self.fail("TODO add branches in RISCV64", .{});
462393 }
463394
464395 // Drop them off at the rbrace.
......@@ -535,12 +466,12 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
535466
536467 .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst),
537468
538 .cmp_lt => try self.airCmp(inst, .lt),
539 .cmp_lte => try self.airCmp(inst, .lte),
540 .cmp_eq => try self.airCmp(inst, .eq),
541 .cmp_gte => try self.airCmp(inst, .gte),
542 .cmp_gt => try self.airCmp(inst, .gt),
543 .cmp_neq => try self.airCmp(inst, .neq),
469 .cmp_lt => try self.airCmp(inst),
470 .cmp_lte => try self.airCmp(inst),
471 .cmp_eq => try self.airCmp(inst),
472 .cmp_gte => try self.airCmp(inst),
473 .cmp_gt => try self.airCmp(inst),
474 .cmp_neq => try self.airCmp(inst),
544475
545476 .cmp_vector => try self.airCmpVector(inst),
546477 .cmp_lt_errors_len => try self.airCmpLtErrorsLen(inst),
......@@ -565,6 +496,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
565496 .frame_addr => try self.airFrameAddress(inst),
566497 .fence => try self.airFence(),
567498 .cond_br => try self.airCondBr(inst),
499 .dbg_stmt => try self.airDbgStmt(inst),
568500 .fptrunc => try self.airFptrunc(inst),
569501 .fpext => try self.airFpext(inst),
570502 .intcast => try self.airIntCast(inst),
......@@ -617,17 +549,17 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
617549 .union_init => try self.airUnionInit(inst),
618550 .prefetch => try self.airPrefetch(inst),
619551 .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"),
623 .try_ptr => @panic("TODO"),
554 .@"try" => return self.fail("TODO: try", .{}),
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),
627557 .dbg_var_ptr,
628558 .dbg_var_val,
629559 => try self.airDbgVar(inst),
630560
561 .dbg_inline_block => try self.airDbgInlineBlock(inst),
562
631563 .call => try self.airCall(inst, .auto),
632564 .call_always_tail => try self.airCall(inst, .always_tail),
633565 .call_never_tail => try self.airCall(inst, .never_tail),
......@@ -1019,17 +951,20 @@ fn binOpRegister(
1019951 const mir_tag: Mir.Inst.Tag = switch (tag) {
1020952 .add => .add,
1021953 .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)}),
1023957 };
1024958 const mir_data: Mir.Inst.Data = switch (tag) {
1025959 .add,
1026960 .sub,
961 .cmp_eq,
1027962 => .{ .r_type = .{
1028963 .rd = dest_reg,
1029964 .rs1 = lhs_reg,
1030965 .rs2 = rhs_reg,
1031966 } },
1032 else => unreachable,
967 else => return self.fail("TODO: binOpRegister {s}", .{@tagName(tag)}),
1033968 };
1034969
1035970 _ = try self.addInst(.{
......@@ -1052,6 +987,8 @@ fn binOpRegister(
1052987/// looks at the lhs and rhs and determines which kind of lowering
1053988/// would be best suitable and then delegates the lowering to other
1054989/// functions.
990///
991/// `maybe_inst` **needs** to be a bin_op, make sure of that.
1055992fn binOp(
1056993 self: *Self,
1057994 tag: Air.Inst.Tag,
......@@ -1066,6 +1003,12 @@ fn binOp(
10661003 // Arithmetic operations on integers and floats
10671004 .add,
10681005 .sub,
1006 .cmp_eq,
1007 .cmp_neq,
1008 .cmp_gt,
1009 .cmp_gte,
1010 .cmp_lt,
1011 .cmp_lte,
10691012 => {
10701013 switch (lhs_ty.zigTypeTag(mod)) {
10711014 .Float => return self.fail("TODO binary operations on floats", .{}),
......@@ -1180,8 +1123,19 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void {
11801123}
11811124
11821125fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1183 _ = inst;
1184 return self.fail("TODO implement airAddWithOverflow for {}", .{self.target.cpu.arch});
1126 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
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 });
11851139}
11861140
11871141fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
......@@ -1352,13 +1306,30 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {
13521306
13531307fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void {
13541308 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 };
13561313 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
13571314}
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
13591330fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {
13601331 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});
13621333 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
13631334}
13641335
......@@ -1500,6 +1471,7 @@ fn reuseOperand(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, op_ind
15001471fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!void {
15011472 const mod = self.bin_file.comp.module.?;
15021473 const elem_ty = ptr_ty.childType(mod);
1474
15031475 switch (ptr) {
15041476 .none => unreachable,
15051477 .undef => unreachable,
......@@ -1507,9 +1479,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
15071479 .dead => unreachable,
15081480 .immediate => |imm| try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm }),
15091481 .ptr_stack_offset => |off| try self.setRegOrMem(elem_ty, dst_mcv, .{ .stack_offset = off }),
1510 .register => {
1511 return self.fail("TODO implement loading from MCValue.register", .{});
1512 },
1482 .register => |src_reg| try self.setRegOrMem(elem_ty, dst_mcv, .{ .register = src_reg }),
15131483 .memory,
15141484 .stack_offset,
15151485 => {
......@@ -1520,6 +1490,10 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
15201490 try self.genSetReg(ptr_ty, reg, ptr);
15211491 try self.load(dst_mcv, .{ .register = reg }, ptr_ty);
15221492 },
1493 .load_symbol => {
1494 const reg = try self.copyToTmpRegister(ptr_ty, ptr);
1495 try self.load(dst_mcv, .{ .register = reg }, ptr_ty);
1496 },
15231497 }
15241498}
15251499
......@@ -1553,6 +1527,8 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
15531527fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type) !void {
15541528 _ = ptr_ty;
15551529
1530 log.debug("storing {s}", .{@tagName(ptr)});
1531
15561532 switch (ptr) {
15571533 .none => unreachable,
15581534 .undef => unreachable,
......@@ -1573,6 +1549,9 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
15731549 .stack_offset => {
15741550 return self.fail("TODO implement storing to MCValue.stack_offset", .{});
15751551 },
1552 .load_symbol => {
1553 return self.fail("TODO implement storing to MCValue.load_symbol", .{});
1554 },
15761555 }
15771556}
15781557
......@@ -1596,27 +1575,32 @@ fn airStore(self: *Self, inst: Air.Inst.Index, safety: bool) !void {
15961575fn airStructFieldPtr(self: *Self, inst: Air.Inst.Index) !void {
15971576 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
15981577 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 });
16001580}
16011581
16021582fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u8) !void {
16031583 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 });
16051586}
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;
16071590 _ = operand;
16081591 _ = ty;
16091592 _ = index;
1610 return self.fail("TODO implement codegen struct_field_ptr", .{});
1611 //return self.finishAir(inst, result, .{ extra.struct_ptr, .none, .none });
1593
1594 return self.fail("TODO: structFieldPtr", .{});
16121595}
16131596
16141597fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
16151598 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
1616 const extra = self.air.extraData(Air.StructField, ty_pl.payload).data;
1617 _ = extra;
1618 return self.fail("TODO implement codegen struct_field_val", .{});
1619 //return self.finishAir(inst, result, .{ extra.struct_ptr, .none, .none });
1599 _ = ty_pl;
1600
1601 return self.fail("TODO: airStructFieldVal", .{});
1602
1603 // return self.finishAir(inst, result, .{ extra.struct_operand, .none, .none });
16201604}
16211605
16221606fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void {
......@@ -1732,12 +1716,13 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
17321716 try self.register_manager.getReg(reg, null);
17331717 try self.genSetReg(arg_ty, reg, arg_mcv);
17341718 },
1735 .stack_offset => {
1736 return self.fail("TODO implement calling with parameters in memory", .{});
1737 },
1719 .stack_offset => |off| try self.genSetStack(arg_ty, off, arg_mcv),
17381720 .ptr_stack_offset => {
17391721 return self.fail("TODO implement calling with MCValue.ptr_stack_offset arg", .{});
17401722 },
1723 .load_symbol => {
1724 return self.fail("TODO implement calling with MCValue.load_symbol", .{});
1725 },
17411726 }
17421727 }
17431728
......@@ -1747,7 +1732,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
17471732 const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, func.owner_decl);
17481733 const sym = elf_file.symbol(sym_index);
17491734 _ = 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);
17511736 try self.genSetReg(Type.usize, .ra, .{ .memory = got_addr });
17521737 _ = try self.addInst(.{
17531738 .tag = .jalr,
......@@ -1830,7 +1815,8 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void {
18301815 //return self.finishAir(inst, .dead, .{ un_op, .none, .none });
18311816}
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)];
18341820 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
18351821 if (self.liveness.isUnused(inst))
18361822 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 {
18421828
18431829 const lhs = try self.resolveInst(bin_op.lhs);
18441830 const rhs = try self.resolveInst(bin_op.rhs);
1845 _ = op;
1846 _ = lhs;
1847 _ = rhs;
1831 const lhs_ty = self.typeOf(bin_op.lhs);
1832 const rhs_ty = self.typeOf(bin_op.rhs);
18481833
1849 return self.fail("TODO implement cmp for {}", .{self.target.cpu.arch});
1850 // return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1834 const result = try self.binOp(tag, null, lhs, rhs, lhs_ty, rhs_ty);
1835
1836 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
18511837}
18521838
18531839fn airCmpVector(self: *Self, inst: Air.Inst.Index) !void {
......@@ -1878,13 +1864,11 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {
18781864}
18791865
18801866fn airDbgInlineBlock(self: *Self, inst: Air.Inst.Index) !void {
1881 const mod = self.bin_file.comp.module.?;
18821867 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
18831868 const extra = self.air.extraData(Air.DbgInlineBlock, ty_pl.payload);
1884 const func = mod.funcInfo(extra.data.func);
1885 // TODO emit debug info for function change
1886 _ = func;
1887 try self.lowerBlock(inst, @ptrCast(self.air.extra[extra.end..][0..extra.data.body_len]));
1869 _ = extra;
1870 // TODO: emit debug info for this block
1871 return self.finishAir(inst, .dead, .{ .none, .none, .none });
18881872}
18891873
18901874fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {
......@@ -1897,10 +1881,165 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {
18971881}
18981882
18991883fn 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});
1903 // return self.finishAir(inst, .unreach, .{ pl_op.operand, .none, .none });
2017 {
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 });
19042043}
19052044
19062045fn isNull(self: *Self, operand: MCValue) !MCValue {
......@@ -2044,25 +2183,26 @@ fn airLoop(self: *Self, inst: Air.Inst.Index) !void {
20442183 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
20452184 const loop = self.air.extraData(Air.Block, ty_pl.payload);
20462185 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
20482189 try self.genBody(body);
20492190 try self.jump(start_index);
2191
20502192 return self.finishAirBookkeeping();
20512193}
20522194
20532195/// Send control flow to the `index` of `self.code`.
2054fn jump(self: *Self, index: usize) !void {
2055 _ = index;
2056 return self.fail("TODO implement jump for {}", .{self.target.cpu.arch});
2196fn jump(self: *Self, index: Mir.Inst.Index) !void {
2197 _ = try self.addInst(.{
2198 .tag = .psuedo_jump,
2199 .data = .{
2200 .inst = index,
2201 },
2202 });
20572203}
20582204
20592205fn 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 {
20662206 try self.blocks.putNoClobber(self.gpa, inst, .{
20672207 // A block is a setup to be able to jump to the end.
20682208 .relocs = .{},
......@@ -2074,10 +2214,16 @@ fn lowerBlock(self: *Self, inst: Air.Inst.Index, body: []const Air.Inst.Index) !
20742214 .mcv = MCValue{ .none = {} },
20752215 });
20762216 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]);
20772221 // TODO emit debug info lexical block
20782222 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
20822228 const result = self.blocks.getPtr(inst).?.mcv;
20832229 return self.finishAir(inst, result, .{ .none, .none, .none });
......@@ -2091,11 +2237,12 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {
20912237 // return self.finishAir(inst, .dead, .{ condition, .none, .none });
20922238}
20932239
2094fn performReloc(self: *Self, reloc: Reloc) !void {
2095 _ = self;
2096 switch (reloc) {
2097 .rel32 => unreachable,
2098 .arm_branch => unreachable,
2240fn performReloc(self: *Self, inst: Mir.Inst.Index) !void {
2241 const tag = self.mir_instructions.items(.tag)[inst];
2242
2243 switch (tag) {
2244 .beq => self.mir_instructions.items(.data)[inst].b_type.imm12 = @intCast(inst),
2245 else => return self.fail("TODO: performReloc {s}", .{@tagName(tag)}),
20992246 }
21002247}
21012248
......@@ -2135,7 +2282,15 @@ fn brVoid(self: *Self, block: Air.Inst.Index) !void {
21352282 // Emit a jump with a relocation. It will be patched up after the block ends.
21362283 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 }));
21392294}
21402295
21412296fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
......@@ -2261,28 +2416,138 @@ fn iterateBigTomb(self: *Self, inst: Air.Inst.Index, operand_count: usize) !BigT
22612416
22622417/// Sets the value without any modifications to register allocation metadata or stack allocation metadata.
22632418fn 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
22642423 switch (loc) {
22652424 .none => return,
22662425 .register => |reg| return self.genSetReg(ty, reg, val),
22672426 .stack_offset => |off| return self.genSetStack(ty, off, val),
2268 .memory => {
2269 return self.fail("TODO implement setRegOrMem for memory", .{});
2270 },
2271 else => unreachable,
2427 else => return self.fail("TODO: setRegOrMem {s}", .{@tagName(loc)}),
22722428 }
22732429}
22742430
22752431fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerError!void {
2276 _ = ty;
2277 _ = stack_offset;
2278 _ = mcv;
2279 return self.fail("TODO implement getSetStack for {}", .{self.target.cpu.arch});
2432 const mod = self.bin_file.comp.module.?;
2433 const abi_size: u32 = @intCast(ty.abiSize(mod));
2434
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", .{});
22802542}
22812543
22822544fn 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
22832548 switch (mcv) {
22842549 .dead => unreachable,
2285 .ptr_stack_offset => unreachable,
2550 .ptr_stack_offset => return self.fail("TODO genSetReg ptr_stack_offset", .{}),
22862551 .unreach, .none => return, // Nothing to do.
22872552 .undef => {
22882553 if (!self.wantSafety())
......@@ -2343,8 +2608,6 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
23432608 });
23442609 },
23452610 .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.
23482611 try self.genSetReg(ty, reg, .{ .immediate = addr });
23492612
23502613 _ = try self.addInst(.{
......@@ -2355,11 +2618,51 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
23552618 .imm12 = 0,
23562619 } },
23572620 });
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 });
23612665 },
2362 else => return self.fail("TODO implement getSetReg for riscv64 {}", .{mcv}),
23632666 }
23642667}
23652668
......@@ -2579,9 +2882,12 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue {
25792882 .mcv => |mcv| switch (mcv) {
25802883 .none => .none,
25812884 .undef => .undef,
2582 .load_got, .load_symbol, .load_direct, .load_tlv => unreachable, // TODO
2885 .load_symbol => |sym_index| .{ .load_symbol = .{ .sym = sym_index } },
25832886 .immediate => |imm| .{ .immediate = imm },
25842887 .memory => |addr| .{ .memory = addr },
2888 .load_got, .load_direct, .load_tlv => {
2889 return self.fail("TODO: genTypedValue {s}", .{@tagName(mcv)});
2890 },
25852891 },
25862892 .fail => |msg| {
25872893 self.err_msg = msg;
......@@ -2634,41 +2940,17 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
26342940 // TODO make this generic with other ABIs, in particular
26352941 // with different hardware floating-point calling
26362942 // conventions
2637 var next_register: usize = 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 };
2943 var stack_offset: u32 = 0;
26452944
26462945 for (fn_info.param_types.get(ip), result.args) |ty, *result_arg| {
2647 const param_size: u32 = @intCast(Type.fromInterned(ty).abiSize(mod));
2648 if (param_size <= 8) {
2649 if (next_register < argument_registers.len) {
2650 result_arg.* = .{ .register = argument_registers[next_register] };
2651 next_register += 1;
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 }
2946 const param_type = Type.fromInterned(ty);
2947 const param_size: u32 = @intCast(param_type.abiSize(mod));
2948
2949 result_arg.* = .{ .stack_offset = stack_offset };
2950 stack_offset += param_size;
26692951 }
26702952
2671 result.stack_byte_count = next_stack_offset;
2953 result.stack_byte_count = stack_offset;
26722954 result.stack_align = .@"16";
26732955 },
26742956 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,
2727/// Relative to the beginning of `code`.
2828prev_di_pc: usize,
2929
30const log = std.log.scoped(.emit);
31
3032const InnerError = error{
3133 OutOfMemory,
3234 EmitFail,
......@@ -37,33 +39,57 @@ pub fn emitMir(
3739) InnerError!void {
3840 const mir_tags = emit.mir.instructions.items(.tag);
3941
42 // TODO: compute branch offsets
43 // try emit.lowerMir();
44
4045 // Emit machine code
4146 for (mir_tags, 0..) |tag, index| {
4247 const inst = @as(u32, @intCast(index));
48 log.debug("emitMir: {s}", .{@tagName(tag)});
4349 switch (tag) {
4450 .add => try emit.mirRType(inst),
4551 .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
4759 .addi => try emit.mirIType(inst),
4860 .jalr => try emit.mirIType(inst),
49 .ld => try emit.mirIType(inst),
50 .sd => try emit.mirIType(inst),
61
62 .jal => try emit.mirJType(inst),
5163
5264 .ebreak => try emit.mirSystem(inst),
5365 .ecall => try emit.mirSystem(inst),
5466 .unimp => try emit.mirSystem(inst),
5567
5668 .dbg_line => try emit.mirDbgLine(inst),
57
5869 .dbg_prologue_end => try emit.mirDebugPrologueEnd(),
5970 .dbg_epilogue_begin => try emit.mirDebugEpilogueBegin(),
6071
72 .psuedo_prologue => try emit.mirPsuedo(inst),
73 .psuedo_jump => try emit.mirPsuedo(inst),
74
6175 .mv => try emit.mirRR(inst),
6276
6377 .nop => try emit.mirNop(inst),
6478 .ret => try emit.mirNop(inst),
6579
6680 .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),
6793 }
6894 }
6995}
......@@ -86,15 +112,19 @@ fn fail(emit: *Emit, comptime format: []const u8, args: anytype) InnerError {
86112 return error.EmitFail;
87113}
88114
89fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void {
90 const delta_line = @as(i32, @intCast(line)) - @as(i32, @intCast(self.prev_di_line));
91 const delta_pc: usize = self.code.items.len - self.prev_di_pc;
92 switch (self.debug_output) {
115fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) !void {
116 log.debug("Line: {} {}\n", .{ line, emit.prev_di_line });
117 const delta_line = @as(i32, @intCast(line)) - @as(i32, @intCast(emit.prev_di_line));
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) {
93121 .dwarf => |dw| {
122 if (column != emit.prev_di_column) try dw.setColumn(column);
123 if (delta_line == 0) return; // TODO: remove this
94124 try dw.advancePCAndLine(delta_line, delta_pc);
95 self.prev_di_line = line;
96 self.prev_di_column = column;
97 self.prev_di_pc = self.code.items.len;
125 emit.prev_di_line = line;
126 emit.prev_di_column = column;
127 emit.prev_di_pc = emit.code.items.len;
98128 },
99129 .plan9 => |dbg_out| {
100130 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 {
113143 // we don't need to do anything, because adding the pc quanta does it for us
114144 } else unreachable;
115145 if (dbg_out.start_line == null)
116 dbg_out.start_line = self.prev_di_line;
146 dbg_out.start_line = emit.prev_di_line;
117147 dbg_out.end_line = line;
118148 // only do this if the pc changed
119 self.prev_di_line = line;
120 self.prev_di_column = column;
121 self.prev_di_pc = self.code.items.len;
149 emit.prev_di_line = line;
150 emit.prev_di_column = column;
151 emit.prev_di_pc = emit.code.items.len;
122152 },
123153 .none => {},
124154 }
......@@ -131,6 +161,19 @@ fn mirRType(emit: *Emit, inst: Mir.Inst.Index) !void {
131161 switch (tag) {
132162 .add => try emit.writeInstruction(Instruction.add(r_type.rd, r_type.rs1, r_type.rs2)),
133163 .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)),
134177 else => unreachable,
135178 }
136179}
......@@ -142,8 +185,30 @@ fn mirIType(emit: *Emit, inst: Mir.Inst.Index) !void {
142185 switch (tag) {
143186 .addi => try emit.writeInstruction(Instruction.addi(i_type.rd, i_type.rs1, i_type.imm12)),
144187 .jalr => try emit.writeInstruction(Instruction.jalr(i_type.rd, i_type.imm12, i_type.rs1)),
188
145189 .ld => try emit.writeInstruction(Instruction.ld(i_type.rd, i_type.imm12, i_type.rs1)),
146190 .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 },
147212 else => unreachable,
148213 }
149214}
......@@ -169,28 +234,55 @@ fn mirDbgLine(emit: *Emit, inst: Mir.Inst.Index) !void {
169234 }
170235}
171236
172fn mirDebugPrologueEnd(self: *Emit) !void {
173 switch (self.debug_output) {
237fn mirDebugPrologueEnd(emit: *Emit) !void {
238 switch (emit.debug_output) {
174239 .dwarf => |dw| {
175240 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);
177242 },
178243 .plan9 => {},
179244 .none => {},
180245 }
181246}
182247
183fn mirDebugEpilogueBegin(self: *Emit) !void {
184 switch (self.debug_output) {
248fn mirDebugEpilogueBegin(emit: *Emit) !void {
249 switch (emit.debug_output) {
185250 .dwarf => |dw| {
186251 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);
188253 },
189254 .plan9 => {},
190255 .none => {},
191256 }
192257}
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
194286fn mirRR(emit: *Emit, inst: Mir.Inst.Index) !void {
195287 const tag = emit.mir.instructions.items(.tag)[inst];
196288 const rr = emit.mir.instructions.items(.data)[inst].rr;
......@@ -200,6 +292,7 @@ fn mirRR(emit: *Emit, inst: Mir.Inst.Index) !void {
200292 else => unreachable,
201293 }
202294}
295
203296fn mirUType(emit: *Emit, inst: Mir.Inst.Index) !void {
204297 const tag = emit.mir.instructions.items(.tag)[inst];
205298 const u_type = emit.mir.instructions.items(.data)[inst].u_type;
......@@ -219,3 +312,63 @@ fn mirNop(emit: *Emit, inst: Mir.Inst.Index) !void {
219312 else => unreachable,
220313 }
221314}
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 {
2424 data: Data,
2525
2626 pub const Tag = enum(u16) {
27 add,
2827 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,
3828 jalr,
39 ld,
4029 lui,
4130 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
4254 nop,
4355 ret,
56
57 /// Load double (64 bits)
58 ld,
59 /// Store double (64 bits)
4460 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,
4693 };
4794
4895 /// The position of an MIR instruction within the `Mir` instructions array.
......@@ -63,7 +110,11 @@ pub const Inst = struct {
63110 /// A 16-bit immediate value.
64111 ///
65112 /// 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,
67118 /// Index into `extra`. Meaning of what can be found there is context-dependent.
68119 ///
69120 /// Used by e.g. load_memory
......@@ -95,6 +146,21 @@ pub const Inst = struct {
95146 rs1: Register,
96147 rs2: Register,
97148 },
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 },
98164 /// U-Type
99165 ///
100166 /// Used by e.g. lui
......@@ -111,10 +177,19 @@ pub const Inst = struct {
111177 },
112178 };
113179
180 const CompareOp = enum {
181 eq,
182 neq,
183 gt,
184 gte,
185 lt,
186 lte,
187 };
188
114189 // 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.
116191 // comptime {
117 // if (!std.debug.runtime_safety) {
192 // if (builtin.mode != .Debug) {
118193 // assert(@sizeOf(Inst) == 8);
119194 // }
120195 // }
......@@ -145,3 +220,9 @@ pub fn extraData(mir: Mir, comptime T: type, index: usize) struct { data: T, end
145220 .end = i,
146221 };
147222}
223
224pub const LoadSymbolPayload = struct {
225 register: u32,
226 atom_index: u32,
227 sym_index: u32,
228};