authorgravatar for david@vortan.devDavid Rubin <david@vortan.dev> 2024-03-29 06:48:41-07:00
committergravatar for david@vortan.devDavid Rubin <david@vortan.dev> 2024-05-11 02:17:11-07:00
log3bf008a3d07b2d9f91964141e1fb33d3fab82390
tree79ddbcce26ac695f979fa75a021463424359dc13
parent350ad90ceec37cb3f152b666377f7f619981a60e

riscv: implement slices


8 files changed, 232 insertions(+), 91 deletions(-)

lib/std/builtin.zig+8-8
...@@ -775,14 +775,14 @@ pub fn default_panic(msg: []const u8, error_return_trace: ?*StackTrace, ret_addr...@@ -775,14 +775,14 @@ pub fn default_panic(msg: []const u8, error_return_trace: ?*StackTrace, ret_addr
775 }775 }
776776
777 if (builtin.zig_backend == .stage2_riscv64) {777 if (builtin.zig_backend == .stage2_riscv64) {
778 // asm volatile ("ecall"778 asm volatile ("ecall"
779 // :779 :
780 // : [number] "{a7}" (64),780 : [number] "{a7}" (64),
781 // [arg1] "{a0}" (1),781 [arg1] "{a0}" (1),
782 // [arg2] "{a1}" (@intFromPtr(msg.ptr)),782 [arg2] "{a1}" (@intFromPtr(msg.ptr)),
783 // [arg3] "{a2}" (msg.len),783 [arg3] "{a2}" (msg.len),
784 // : "rcx", "r11", "memory"784 : "rcx", "r11", "memory"
785 // );785 );
786 std.posix.exit(127);786 std.posix.exit(127);
787 }787 }
788788
src/arch/riscv64/CodeGen.zig+138-70
...@@ -122,9 +122,10 @@ const MCValue = union(enum) {...@@ -122,9 +122,10 @@ const MCValue = union(enum) {
122 /// A pointer-sized integer that fits in a register.122 /// A pointer-sized integer that fits in a register.
123 /// If the type is a pointer, this is the pointer address in virtual address space.123 /// If the type is a pointer, this is the pointer address in virtual address space.
124 immediate: u64,124 immediate: u64,
125 /// The value is in memory at an address not-yet-allocated by the linker.125 /// The value doesn't exist in memory yet.
126 /// This traditionally corresponds to a relocation emitted in a relocatable object file.
127 load_symbol: SymbolOffset,126 load_symbol: SymbolOffset,
127 /// The address of the memory location not-yet-allocated by the linker.
128 addr_symbol: SymbolOffset,
128 /// The value is in a target-specific register.129 /// The value is in a target-specific register.
129 register: Register,130 register: Register,
130 /// The value is split across two registers131 /// The value is split across two registers
...@@ -169,6 +170,7 @@ const MCValue = union(enum) {...@@ -169,6 +170,7 @@ const MCValue = union(enum) {
169 .indirect,170 .indirect,
170 .undef,171 .undef,
171 .load_symbol,172 .load_symbol,
173 .addr_symbol,
172 .air_ref,174 .air_ref,
173 => false,175 => false,
174176
...@@ -188,10 +190,14 @@ const MCValue = union(enum) {...@@ -188,10 +190,14 @@ const MCValue = union(enum) {
188 .immediate,190 .immediate,
189 .ptr_stack_offset,191 .ptr_stack_offset,
190 .register_offset,192 .register_offset,
193 .register_pair,
194 .register,
191 .undef,195 .undef,
192 .air_ref,196 .air_ref,
197 .addr_symbol,
193 => unreachable, // not in memory198 => unreachable, // not in memory
194199
200 .load_symbol => |sym_off| .{ .addr_symbol = sym_off },
195 .memory => |addr| .{ .immediate = addr },201 .memory => |addr| .{ .immediate = addr },
196 .stack_offset => |off| .{ .ptr_stack_offset = off },202 .stack_offset => |off| .{ .ptr_stack_offset = off },
197 .indirect => |reg_off| switch (reg_off.off) {203 .indirect => |reg_off| switch (reg_off.off) {
...@@ -219,6 +225,7 @@ const MCValue = union(enum) {...@@ -219,6 +225,7 @@ const MCValue = union(enum) {
219 .ptr_stack_offset => |off| .{ .stack_offset = off },225 .ptr_stack_offset => |off| .{ .stack_offset = off },
220 .register => |reg| .{ .indirect = .{ .reg = reg } },226 .register => |reg| .{ .indirect = .{ .reg = reg } },
221 .register_offset => |reg_off| .{ .indirect = reg_off },227 .register_offset => |reg_off| .{ .indirect = reg_off },
228 .addr_symbol => |sym_off| .{ .load_symbol = sym_off },
222 };229 };
223 }230 }
224231
...@@ -235,6 +242,7 @@ const MCValue = union(enum) {...@@ -235,6 +242,7 @@ const MCValue = union(enum) {
235 .indirect,242 .indirect,
236 .stack_offset,243 .stack_offset,
237 .load_symbol,244 .load_symbol,
245 .addr_symbol,
238 => switch (off) {246 => switch (off) {
239 0 => mcv,247 0 => mcv,
240 else => unreachable, // not offsettable248 else => unreachable, // not offsettable
...@@ -801,6 +809,43 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void {...@@ -801,6 +809,43 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void {
801 try table.ensureUnusedCapacity(self.gpa, additional_count);809 try table.ensureUnusedCapacity(self.gpa, additional_count);
802}810}
803811
812fn splitType(self: *Self, ty: Type) ![2]Type {
813 const mod = self.bin_file.comp.module.?;
814 const classes = mem.sliceTo(&abi.classifySystemV(ty, mod), .none);
815 var parts: [2]Type = undefined;
816 if (classes.len == 2) for (&parts, classes, 0..) |*part, class, part_i| {
817 part.* = switch (class) {
818 .integer => switch (part_i) {
819 0 => Type.u64,
820 1 => part: {
821 const elem_size = ty.abiAlignment(mod).minStrict(.@"8").toByteUnitsOptional().?;
822 const elem_ty = try mod.intType(.unsigned, @intCast(elem_size * 8));
823 break :part switch (@divExact(ty.abiSize(mod) - 8, elem_size)) {
824 1 => elem_ty,
825 else => |len| try mod.arrayType(.{ .len = len, .child = elem_ty.toIntern() }),
826 };
827 },
828 else => unreachable,
829 },
830 else => break,
831 };
832 } else if (parts[0].abiSize(mod) + parts[1].abiSize(mod) == ty.abiSize(mod)) return parts;
833 return std.debug.panic("TODO implement splitType for {}", .{ty.fmt(mod)});
834}
835
836fn symbolIndex(self: *Self) !u32 {
837 const mod = self.bin_file.comp.module.?;
838 const decl_index = mod.funcOwnerDeclIndex(self.func_index);
839 return switch (self.bin_file.tag) {
840 .elf => blk: {
841 const elf_file = self.bin_file.cast(link.File.Elf).?;
842 const atom_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, decl_index);
843 break :blk atom_index;
844 },
845 else => return self.fail("TODO genSetReg load_symbol for {s}", .{@tagName(self.bin_file.tag)}),
846 };
847}
848
804fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: Alignment) !u32 {849fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: Alignment) !u32 {
805 self.stack_align = self.stack_align.max(abi_align);850 self.stack_align = self.stack_align.max(abi_align);
806 // TODO find a free slot instead of always appending851 // TODO find a free slot instead of always appending
...@@ -1610,40 +1655,41 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {...@@ -1610,40 +1655,41 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {
16101655
1611fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void {1656fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void {
1612 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;1657 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
1613 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {1658 const result = result: {
1614 const mcv = try self.resolveInst(ty_op.operand);1659 const src_mcv = try self.resolveInst(ty_op.operand);
1615 break :result try self.slicePtr(mcv);1660 if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) break :result src_mcv;
1661
1662 const dst_mcv = try self.allocRegOrMem(inst, true);
1663 const dst_ty = self.typeOfIndex(inst);
1664 try self.genCopy(dst_ty, dst_mcv, src_mcv);
1665 break :result dst_mcv;
1616 };1666 };
1617 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });1667 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1618}1668}
16191669
1620fn slicePtr(self: *Self, mcv: MCValue) !MCValue {
1621 switch (mcv) {
1622 .dead, .unreach, .none => unreachable,
1623 .register => unreachable, // a slice doesn't fit in one register
1624 .stack_offset => |off| {
1625 return MCValue{ .stack_offset = off };
1626 },
1627 .memory => |addr| {
1628 return MCValue{ .memory = addr };
1629 },
1630 else => return self.fail("TODO slicePtr {s}", .{@tagName(mcv)}),
1631 }
1632}
1633
1634fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {1670fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {
1635 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;1671 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
1636 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {1672 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1637 const ptr_bits = 64;1673 const src_mcv = try self.resolveInst(ty_op.operand);
1638 const ptr_bytes = @divExact(ptr_bits, 8);1674 switch (src_mcv) {
1639 const mcv = try self.resolveInst(ty_op.operand);
1640 switch (mcv) {
1641 .dead, .unreach, .none => unreachable,
1642 .register => unreachable, // a slice doesn't fit in one register
1643 .stack_offset => |off| {1675 .stack_offset => |off| {
1644 break :result MCValue{ .stack_offset = off + ptr_bytes };1676 const len_mcv: MCValue = .{ .stack_offset = off + 8 };
1677 if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) break :result len_mcv;
1678
1679 const dst_mcv = try self.allocRegOrMem(inst, true);
1680 try self.genCopy(Type.usize, dst_mcv, len_mcv);
1681 break :result dst_mcv;
1682 },
1683 .register_pair => |pair| {
1684 const len_mcv: MCValue = .{ .register = pair[1] };
1685
1686 if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) break :result len_mcv;
1687
1688 const dst_mcv = try self.allocRegOrMem(inst, true);
1689 try self.genCopy(Type.usize, dst_mcv, len_mcv);
1690 break :result dst_mcv;
1645 },1691 },
1646 else => return self.fail("TODO airSliceLen for {}", .{mcv}),1692 else => return self.fail("TODO airSliceLen for {}", .{src_mcv}),
1647 }1693 }
1648 };1694 };
1649 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });1695 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
...@@ -1978,6 +2024,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr_mcv: MCValue, ptr_ty: Type) InnerErro...@@ -1978,6 +2024,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr_mcv: MCValue, ptr_ty: Type) InnerErro
1978 .register,2024 .register,
1979 .register_offset,2025 .register_offset,
1980 .ptr_stack_offset,2026 .ptr_stack_offset,
2027 .addr_symbol,
1981 => try self.genCopy(dst_ty, dst_mcv, ptr_mcv.deref()),2028 => try self.genCopy(dst_ty, dst_mcv, ptr_mcv.deref()),
19822029
1983 .memory,2030 .memory,
...@@ -2019,11 +2066,6 @@ fn store(self: *Self, pointer: MCValue, value: MCValue, ptr_ty: Type, value_ty:...@@ -2019,11 +2066,6 @@ fn store(self: *Self, pointer: MCValue, value: MCValue, ptr_ty: Type, value_ty:
20192066
2020 log.debug("storing {}:{} in {}:{}", .{ value, value_ty.fmt(mod), pointer, ptr_ty.fmt(mod) });2067 log.debug("storing {}:{} in {}:{}", .{ value, value_ty.fmt(mod), pointer, ptr_ty.fmt(mod) });
20212068
2022 if (value_ty.isSlice(mod)) {
2023 // cheat a bit by loading in two parts
2024
2025 }
2026
2027 switch (pointer) {2069 switch (pointer) {
2028 .none => unreachable,2070 .none => unreachable,
2029 .undef => unreachable,2071 .undef => unreachable,
...@@ -2192,7 +2234,11 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {...@@ -2192,7 +2234,11 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
21922234
2193 const dst_mcv = switch (src_mcv) {2235 const dst_mcv = switch (src_mcv) {
2194 .register => |src_reg| dst: {2236 .register => |src_reg| dst: {
2195 try self.register_manager.getReg(src_reg, null);2237 self.register_manager.getRegAssumeFree(src_reg, null);
2238 break :dst src_mcv;
2239 },
2240 .register_pair => |pair| dst: {
2241 for (pair) |reg| self.register_manager.getRegAssumeFree(reg, null);
2196 break :dst src_mcv;2242 break :dst src_mcv;
2197 },2243 },
2198 else => return self.fail("TODO: airArg {s}", .{@tagName(src_mcv)}),2244 else => return self.fail("TODO: airArg {s}", .{@tagName(src_mcv)}),
...@@ -3056,6 +3102,8 @@ fn iterateBigTomb(self: *Self, inst: Air.Inst.Index, operand_count: usize) !BigT...@@ -3056,6 +3102,8 @@ fn iterateBigTomb(self: *Self, inst: Air.Inst.Index, operand_count: usize) !BigT
30563102
3057/// Sets the value without any modifications to register allocation metadata or stack allocation metadata.3103/// Sets the value without any modifications to register allocation metadata or stack allocation metadata.
3058fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void {3104fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void {
3105 const mod = self.bin_file.comp.module.?;
3106
3059 // There isn't anything to store3107 // There isn't anything to store
3060 if (dst_mcv == .none) return;3108 if (dst_mcv == .none) return;
30613109
...@@ -3066,7 +3114,6 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void {...@@ -3066,7 +3114,6 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void {
30663114
3067 switch (dst_mcv) {3115 switch (dst_mcv) {
3068 .register => |reg| return self.genSetReg(ty, reg, src_mcv),3116 .register => |reg| return self.genSetReg(ty, reg, src_mcv),
3069 .register_pair => |pair| return self.genSetRegPair(ty, pair, src_mcv),
3070 .register_offset => |dst_reg_off| try self.genSetReg(ty, dst_reg_off.reg, switch (src_mcv) {3117 .register_offset => |dst_reg_off| try self.genSetReg(ty, dst_reg_off.reg, switch (src_mcv) {
3071 .none,3118 .none,
3072 .unreach,3119 .unreach,
...@@ -3084,7 +3131,47 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void {...@@ -3084,7 +3131,47 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void {
3084 }),3131 }),
3085 .stack_offset => |off| return self.genSetStack(ty, off, src_mcv),3132 .stack_offset => |off| return self.genSetStack(ty, off, src_mcv),
3086 .memory => |addr| return self.genSetMem(ty, addr, src_mcv),3133 .memory => |addr| return self.genSetMem(ty, addr, src_mcv),
3087 else => return self.fail("TODO: genCopy {s} with {s}", .{ @tagName(dst_mcv), @tagName(src_mcv) }),3134 .register_pair => |dst_regs| {
3135 const src_info: ?struct { addr_reg: Register, addr_lock: RegisterLock } = switch (src_mcv) {
3136 .register_pair, .memory, .indirect, .stack_offset => null,
3137 .load_symbol => src: {
3138 const src_addr_reg, const src_addr_lock = try self.allocReg();
3139 errdefer self.register_manager.unlockReg(src_addr_lock);
3140
3141 try self.genSetReg(Type.usize, src_addr_reg, src_mcv.address());
3142 break :src .{ .addr_reg = src_addr_reg, .addr_lock = src_addr_lock };
3143 },
3144 .air_ref => |src_ref| return self.genCopy(
3145 ty,
3146 dst_mcv,
3147 try self.resolveInst(src_ref),
3148 ),
3149 else => return self.fail("TODO implement genCopy for {s} of {}", .{
3150 @tagName(src_mcv), ty.fmt(mod),
3151 }),
3152 };
3153 defer if (src_info) |info| self.register_manager.unlockReg(info.addr_lock);
3154
3155 switch (ty.zigTypeTag(mod)) {
3156 .Optional => return,
3157 else => {},
3158 }
3159
3160 var part_disp: i32 = 0;
3161 for (dst_regs, try self.splitType(ty), 0..) |dst_reg, dst_ty, part_i| {
3162 try self.genSetReg(dst_ty, dst_reg, switch (src_mcv) {
3163 .register_pair => |src_regs| .{ .register = src_regs[part_i] },
3164 .memory, .indirect, .stack_offset => src_mcv.address().offset(part_disp).deref(),
3165 .load_symbol => .{ .indirect = .{
3166 .reg = src_info.?.addr_reg,
3167 .off = part_disp,
3168 } },
3169 else => unreachable,
3170 });
3171 part_disp += @intCast(dst_ty.abiSize(mod));
3172 }
3173 },
3174 else => return std.debug.panic("TODO: genCopy {s} with {s}", .{ @tagName(dst_mcv), @tagName(src_mcv) }),
3088 }3175 }
3089}3176}
30903177
...@@ -3168,14 +3255,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, src_mcv: MCValue) Inner...@@ -3168,14 +3255,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, src_mcv: MCValue) Inner
3168 try self.genSetReg(ptr_ty, src_reg, .{ .ptr_stack_offset = offset });3255 try self.genSetReg(ptr_ty, src_reg, .{ .ptr_stack_offset = offset });
3169 },3256 },
3170 .load_symbol => |sym_off| {3257 .load_symbol => |sym_off| {
3171 const atom_index = atom: {3258 const atom_index = try self.symbolIndex();
3172 const decl_index = mod.funcOwnerDeclIndex(self.func_index);
3173
3174 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
3175 const atom_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, decl_index);
3176 break :atom atom_index;
3177 } else return self.fail("TODO genSetStack for {s}", .{@tagName(self.bin_file.tag)});
3178 };
31793259
3180 // setup the src pointer3260 // setup the src pointer
3181 _ = try self.addInst(.{3261 _ = try self.addInst(.{
...@@ -3443,16 +3523,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, src_mcv: MCValue) InnerError!...@@ -3443,16 +3523,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
3443 .load_symbol => |sym_off| {3523 .load_symbol => |sym_off| {
3444 assert(sym_off.off == 0);3524 assert(sym_off.off == 0);
34453525
3446 const decl_index = mod.funcOwnerDeclIndex(self.func_index);3526 const atom_index = try self.symbolIndex();
34473527
3448 const atom_index = switch (self.bin_file.tag) {
3449 .elf => blk: {
3450 const elf_file = self.bin_file.cast(link.File.Elf).?;
3451 const atom_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, decl_index);
3452 break :blk atom_index;
3453 },
3454 else => return self.fail("TODO genSetReg load_symbol for {s}", .{@tagName(self.bin_file.tag)}),
3455 };
3456 _ = try self.addInst(.{3528 _ = try self.addInst(.{
3457 .tag = .load_symbol,3529 .tag = .load_symbol,
3458 .data = .{3530 .data = .{
...@@ -3485,27 +3557,23 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, src_mcv: MCValue) InnerError!...@@ -3485,27 +3557,23 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
3485 },3557 },
3486 });3558 });
3487 },3559 },
3488 else => return self.fail("TODO: genSetReg {s}", .{@tagName(src_mcv)}),3560 .addr_symbol => |sym_off| {
3489 }3561 assert(sym_off.off == 0);
3490}
3491
3492fn genSetRegPair(self: *Self, ty: Type, pair: [2]Register, src_mcv: MCValue) InnerError!void {
3493 const mod = self.bin_file.comp.module.?;
3494 const abi_size: u32 = @intCast(ty.abiSize(mod));
3495
3496 assert(abi_size > 8 and abi_size <= 16); // must fit only fit into two registers
34973562
3498 switch (src_mcv) {3563 const atom_index = try self.symbolIndex();
3499 .air_ref => |ref| return self.genSetRegPair(ty, pair, try self.resolveInst(ref)),
3500 .load_symbol => |sym_off| {
3501 _ = sym_off;
3502 // return self.fail("TODO: genSetRegPair load_symbol", .{});
3503 // commented out just for testing.
35043564
3505 // plan here is to load the address into a temporary register and3565 _ = try self.addInst(.{
3506 // copy into the pair.3566 .tag = .load_symbol,
3567 .data = .{
3568 .payload = try self.addExtra(Mir.LoadSymbolPayload{
3569 .register = reg.id(),
3570 .atom_index = atom_index,
3571 .sym_index = sym_off.sym,
3572 }),
3573 },
3574 });
3507 },3575 },
3508 else => return self.fail("TODO: genSetRegPair {s}", .{@tagName(src_mcv)}),3576 else => return self.fail("TODO: genSetReg {s}", .{@tagName(src_mcv)}),
3509 }3577 }
3510}3578}
35113579
src/arch/riscv64/Emit.zig+22-8
...@@ -398,7 +398,7 @@ fn mirPsuedo(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -398,7 +398,7 @@ fn mirPsuedo(emit: *Emit, inst: Mir.Inst.Index) !void {
398398
399 .j => {399 .j => {
400 const offset = @as(i64, @intCast(emit.code_offset_mapping.get(data.inst).?)) - @as(i64, @intCast(emit.code.items.len));400 const offset = @as(i64, @intCast(emit.code_offset_mapping.get(data.inst).?)) - @as(i64, @intCast(emit.code.items.len));
401 try emit.writeInstruction(Instruction.jal(.s0, @intCast(offset)));401 try emit.writeInstruction(Instruction.jal(.zero, @intCast(offset)));
402 },402 },
403403
404 else => unreachable,404 else => unreachable,
...@@ -443,27 +443,40 @@ fn mirLoadSymbol(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -443,27 +443,40 @@ fn mirLoadSymbol(emit: *Emit, inst: Mir.Inst.Index) !void {
443 const data = emit.mir.extraData(Mir.LoadSymbolPayload, payload).data;443 const data = emit.mir.extraData(Mir.LoadSymbolPayload, payload).data;
444 const reg = @as(Register, @enumFromInt(data.register));444 const reg = @as(Register, @enumFromInt(data.register));
445445
446 const end_offset = @as(u32, @intCast(emit.code.items.len));446 const start_offset = @as(u32, @intCast(emit.code.items.len));
447 try emit.writeInstruction(Instruction.lui(reg, 0));447 try emit.writeInstruction(Instruction.lui(reg, 0));
448 try emit.writeInstruction(Instruction.lw(reg, 0, reg));
449448
450 switch (emit.bin_file.tag) {449 switch (emit.bin_file.tag) {
451 .elf => {450 .elf => {
452 const elf_file = emit.bin_file.cast(link.File.Elf).?;451 const elf_file = emit.bin_file.cast(link.File.Elf).?;
453 const atom_ptr = elf_file.symbol(data.atom_index).atom(elf_file).?;452 const atom_ptr = elf_file.symbol(data.atom_index).atom(elf_file).?;
453 const sym_index = elf_file.zigObjectPtr().?.symbol(data.sym_index);
454 const sym = elf_file.symbol(sym_index);
454455
455 const hi_r_type = @intFromEnum(std.elf.R_RISCV.HI20);456 var hi_r_type: u32 = @intFromEnum(std.elf.R_RISCV.HI20);
457 var lo_r_type: u32 = @intFromEnum(std.elf.R_RISCV.LO12_I);
458
459 if (sym.flags.needs_zig_got) {
460 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
461
462 hi_r_type = Elf.R_ZIG_GOT_HI20;
463 lo_r_type = Elf.R_ZIG_GOT_LO12;
464
465 // we need to deref once if we are getting from zig_got, as itll
466 // reloc an address of the address in the got.
467 try emit.writeInstruction(Instruction.ld(reg, 0, reg));
468 } else {
469 try emit.writeInstruction(Instruction.addi(reg, reg, 0));
470 }
456471
457 try atom_ptr.addReloc(elf_file, .{472 try atom_ptr.addReloc(elf_file, .{
458 .r_offset = end_offset,473 .r_offset = start_offset,
459 .r_info = (@as(u64, @intCast(data.sym_index)) << 32) | hi_r_type,474 .r_info = (@as(u64, @intCast(data.sym_index)) << 32) | hi_r_type,
460 .r_addend = 0,475 .r_addend = 0,
461 });476 });
462477
463 const lo_r_type = @intFromEnum(std.elf.R_RISCV.LO12_I);
464
465 try atom_ptr.addReloc(elf_file, .{478 try atom_ptr.addReloc(elf_file, .{
466 .r_offset = end_offset + 4,479 .r_offset = start_offset + 4,
467 .r_info = (@as(u64, @intCast(data.sym_index)) << 32) | lo_r_type,480 .r_info = (@as(u64, @intCast(data.sym_index)) << 32) | lo_r_type,
468 .r_addend = 0,481 .r_addend = 0,
469 });482 });
...@@ -587,6 +600,7 @@ const bits = @import("bits.zig");...@@ -587,6 +600,7 @@ const bits = @import("bits.zig");
587const abi = @import("abi.zig");600const abi = @import("abi.zig");
588const link = @import("../../link.zig");601const link = @import("../../link.zig");
589const Module = @import("../../Module.zig");602const Module = @import("../../Module.zig");
603const Elf = @import("../../link/Elf.zig");
590const ErrorMsg = Module.ErrorMsg;604const ErrorMsg = Module.ErrorMsg;
591const assert = std.debug.assert;605const assert = std.debug.assert;
592const Instruction = bits.Instruction;606const Instruction = bits.Instruction;
src/arch/riscv64/Mir.zig+3-1
...@@ -118,7 +118,9 @@ pub const Inst = struct {...@@ -118,7 +118,9 @@ pub const Inst = struct {
118 /// function epilogue118 /// function epilogue
119 psuedo_epilogue,119 psuedo_epilogue,
120120
121 // TODO: add description121 /// Loads the address of a value that hasn't yet been allocated in memory.
122 ///
123 /// uses the Mir.LoadSymbolPayload payload.
122 load_symbol,124 load_symbol,
123125
124 // TODO: add description126 // TODO: add description
src/arch/riscv64/abi.zig+32-1
...@@ -5,7 +5,7 @@ const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;...@@ -5,7 +5,7 @@ const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;
5const Type = @import("../../type.zig").Type;5const Type = @import("../../type.zig").Type;
6const Module = @import("../../Module.zig");6const Module = @import("../../Module.zig");
77
8pub const Class = enum { memory, byval, integer, double_integer, fields };8pub const Class = enum { memory, byval, integer, double_integer, fields, none };
99
10pub fn classifyType(ty: Type, mod: *Module) Class {10pub fn classifyType(ty: Type, mod: *Module) Class {
11 const target = mod.getTarget();11 const target = mod.getTarget();
...@@ -91,6 +91,37 @@ pub fn classifyType(ty: Type, mod: *Module) Class {...@@ -91,6 +91,37 @@ pub fn classifyType(ty: Type, mod: *Module) Class {
91 }91 }
92}92}
9393
94/// There are a maximum of 8 possible return slots. Returned values are in
95/// the beginning of the array; unused slots are filled with .none.
96pub fn classifySystemV(ty: Type, mod: *Module) [8]Class {
97 const memory_class = [_]Class{
98 .memory, .none, .none, .none,
99 .none, .none, .none, .none,
100 };
101 var result = [1]Class{.none} ** 8;
102 switch (ty.zigTypeTag(mod)) {
103 .Pointer => switch (ty.ptrSize(mod)) {
104 .Slice => {
105 result[0] = .integer;
106 result[1] = .integer;
107 return result;
108 },
109 else => {
110 result[0] = .integer;
111 return result;
112 },
113 },
114 .Optional => {
115 if (ty.isPtrLikeOptional(mod)) {
116 result[0] = .integer;
117 return result;
118 }
119 return memory_class;
120 },
121 else => return result,
122 }
123}
124
94pub const callee_preserved_regs = [_]Register{125pub const callee_preserved_regs = [_]Register{
95 .s0, .s1, .s2, .s3, .s4, .s5, .s6, .s7, .s8, .s9, .s10, .s11,126 .s0, .s1, .s2, .s3, .s4, .s5, .s6, .s7, .s8, .s9, .s10, .s11,
96};127};
src/codegen/llvm.zig+2
...@@ -11132,6 +11132,7 @@ fn lowerFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Error!Bu...@@ -11132,6 +11132,7 @@ fn lowerFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Error!Bu
11132 }11132 }
11133 return o.builder.structType(.normal, types[0..types_len]);11133 return o.builder.structType(.normal, types[0..types_len]);
11134 },11134 },
11135 .none => unreachable,
11135 }11136 }
11136 },11137 },
11137 // TODO investigate C ABI for other architectures11138 // TODO investigate C ABI for other architectures
...@@ -11389,6 +11390,7 @@ const ParamTypeIterator = struct {...@@ -11389,6 +11390,7 @@ const ParamTypeIterator = struct {
11389 it.llvm_index += it.types_len - 1;11390 it.llvm_index += it.types_len - 1;
11390 return .multiple_llvm_types;11391 return .multiple_llvm_types;
11391 },11392 },
11393 .none => unreachable,
11392 }11394 }
11393 },11395 },
11394 // TODO investigate C ABI for other architectures11396 // TODO investigate C ABI for other architectures
src/link/Elf.zig+2
...@@ -6409,6 +6409,8 @@ const RelaSectionTable = std.AutoArrayHashMapUnmanaged(u32, RelaSection);...@@ -6409,6 +6409,8 @@ const RelaSectionTable = std.AutoArrayHashMapUnmanaged(u32, RelaSection);
6409// TODO: add comptime check we don't clobber any reloc for any ISA6409// TODO: add comptime check we don't clobber any reloc for any ISA
6410pub const R_ZIG_GOT32: u32 = 0xff00;6410pub const R_ZIG_GOT32: u32 = 0xff00;
6411pub const R_ZIG_GOTPCREL: u32 = 0xff01;6411pub const R_ZIG_GOTPCREL: u32 = 0xff01;
6412pub const R_ZIG_GOT_HI20: u32 = 0xff02;
6413pub const R_ZIG_GOT_LO12: u32 = 0xff03;
64126414
6413fn defaultEntrySymbolName(cpu_arch: std.Target.Cpu.Arch) []const u8 {6415fn defaultEntrySymbolName(cpu_arch: std.Target.Cpu.Arch) []const u8 {
6414 return switch (cpu_arch) {6416 return switch (cpu_arch) {
src/link/Elf/Atom.zig+25-3
...@@ -2025,7 +2025,15 @@ const riscv = struct {...@@ -2025,7 +2025,15 @@ const riscv = struct {
2025 .SUB32,2025 .SUB32,
2026 => {},2026 => {},
20272027
2028 else => try atom.reportUnhandledRelocError(rel, elf_file),2028 else => |x| switch (@intFromEnum(x)) {
2029 Elf.R_ZIG_GOT_HI20,
2030 Elf.R_ZIG_GOT_LO12,
2031 => {
2032 assert(symbol.flags.has_zig_got);
2033 },
2034
2035 else => try atom.reportUnhandledRelocError(rel, elf_file),
2036 },
2029 }2037 }
2030 }2038 }
20312039
...@@ -2046,7 +2054,6 @@ const riscv = struct {...@@ -2046,7 +2054,6 @@ const riscv = struct {
2046 const P, const A, const S, const GOT, const G, const TP, const DTP, const ZIG_GOT = args;2054 const P, const A, const S, const GOT, const G, const TP, const DTP, const ZIG_GOT = args;
2047 _ = TP;2055 _ = TP;
2048 _ = DTP;2056 _ = DTP;
2049 _ = ZIG_GOT;
20502057
2051 switch (r_type) {2058 switch (r_type) {
2052 .NONE => unreachable,2059 .NONE => unreachable,
...@@ -2136,7 +2143,22 @@ const riscv = struct {...@@ -2136,7 +2143,22 @@ const riscv = struct {
2136 }2143 }
2137 },2144 },
21382145
2139 else => try atom.reportUnhandledRelocError(rel, elf_file),2146 else => |x| switch (@intFromEnum(x)) {
2147 // Zig custom relocations
2148 Elf.R_ZIG_GOT_HI20 => {
2149 assert(target.flags.has_zig_got);
2150 const disp: u32 = @bitCast(math.cast(i32, G + ZIG_GOT + A) orelse return error.Overflow);
2151 riscv_util.writeInstU(code[r_offset..][0..4], disp);
2152 },
2153
2154 Elf.R_ZIG_GOT_LO12 => {
2155 assert(target.flags.has_zig_got);
2156 const value: u32 = @bitCast(math.cast(i32, G + ZIG_GOT + A) orelse return error.Overflow);
2157 riscv_util.writeInstI(code[r_offset..][0..4], value);
2158 },
2159
2160 else => try atom.reportUnhandledRelocError(rel, elf_file),
2161 },
2140 }2162 }
2141 }2163 }
21422164