Skip to content

Commit

Permalink
riscv: by-value structs + @min
Browse files Browse the repository at this point in the history
  • Loading branch information
Rexicon226 committed May 11, 2024
1 parent a30af17 commit 2fd83d8
Show file tree
Hide file tree
Showing 15 changed files with 174 additions and 35 deletions.
99 changes: 89 additions & 10 deletions src/arch/riscv64/CodeGen.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1800,8 +1800,95 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {
}

fn airMin(self: *Self, inst: Air.Inst.Index) !void {
const zcu = self.bin_file.comp.module.?;
const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement min for {}", .{self.target.cpu.arch});

const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
const lhs = try self.resolveInst(bin_op.lhs);
const rhs = try self.resolveInst(bin_op.rhs);
const lhs_ty = self.typeOf(bin_op.lhs);
const rhs_ty = self.typeOf(bin_op.rhs);

const int_info = lhs_ty.intInfo(zcu);

if (int_info.bits > 64) return self.fail("TODO: > 64 bit @min", .{});

const lhs_reg, const lhs_lock = blk: {
if (lhs == .register) break :blk .{ lhs.register, null };

const lhs_reg, const lhs_lock = try self.allocReg();
try self.genSetReg(lhs_ty, lhs_reg, lhs);
break :blk .{ lhs_reg, lhs_lock };
};
defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);

const rhs_reg, const rhs_lock = blk: {
if (rhs == .register) break :blk .{ rhs.register, null };

const rhs_reg, const rhs_lock = try self.allocReg();
try self.genSetReg(rhs_ty, rhs_reg, rhs);
break :blk .{ rhs_reg, rhs_lock };
};
defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);

const mask_reg, const mask_lock = try self.allocReg();
defer self.register_manager.unlockReg(mask_lock);

const result_reg, const result_lock = try self.allocReg();
defer self.register_manager.unlockReg(result_lock);

_ = try self.addInst(.{
.tag = if (int_info.signedness == .unsigned) .sltu else .slt,
.ops = .rrr,
.data = .{ .r_type = .{
.rd = mask_reg,
.rs1 = lhs_reg,
.rs2 = rhs_reg,
} },
});

_ = try self.addInst(.{
.tag = .sub,
.ops = .rrr,
.data = .{ .r_type = .{
.rd = mask_reg,
.rs1 = .zero,
.rs2 = mask_reg,
} },
});

_ = try self.addInst(.{
.tag = .xor,
.ops = .rrr,
.data = .{ .r_type = .{
.rd = result_reg,
.rs1 = lhs_reg,
.rs2 = rhs_reg,
} },
});

_ = try self.addInst(.{
.tag = .@"and",
.ops = .rrr,
.data = .{ .r_type = .{
.rd = mask_reg,
.rs1 = result_reg,
.rs2 = mask_reg,
} },
});

_ = try self.addInst(.{
.tag = .xor,
.ops = .rrr,
.data = .{ .r_type = .{
.rd = result_reg,
.rs1 = rhs_reg,
.rs2 = mask_reg,
} },
});

break :result .{ .register = result_reg };
};
return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
}

Expand Down Expand Up @@ -3513,17 +3600,9 @@ fn genCall(
.imm12 = Immediate.s(0),
} },
});
} else if (self.bin_file.cast(link.File.Coff)) |_| {
return self.fail("TODO implement calling in COFF for {}", .{self.target.cpu.arch});
} else if (self.bin_file.cast(link.File.MachO)) |_| {
unreachable; // unsupported architecture for MachO
} else if (self.bin_file.cast(link.File.Plan9)) |_| {
return self.fail("TODO implement call on plan9 for {}", .{self.target.cpu.arch});
} else unreachable;
},
.extern_func => {
return self.fail("TODO: extern func calls", .{});
},
.extern_func => return self.fail("TODO: extern func calls", .{}),
else => return self.fail("TODO implement calling bitcasted functions", .{}),
}
} else {
Expand Down
7 changes: 5 additions & 2 deletions src/arch/riscv64/Encoding.zig
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ pub const Mnemonic = enum {
lb,
lbu,
sltiu,
sltu,
xori,
andi,
slli,
Expand All @@ -38,9 +37,11 @@ pub const Mnemonic = enum {

// R Type
add,
@"and",
sub,
slt,
mul,
sltu,
xor,

// System
Expand All @@ -52,6 +53,8 @@ pub const Mnemonic = enum {
return switch (mnem) {
// zig fmt: off
.add => .{ .opcode = 0b0110011, .funct3 = 0b000, .funct7 = 0b0000000 },
.sltu => .{ .opcode = 0b0110011, .funct3 = 0b011, .funct7 = 0b0000000 },
.@"and" => .{ .opcode = 0b0110011, .funct3 = 0b111, .funct7 = 0b0000000 },
.sub => .{ .opcode = 0b0110011, .funct3 = 0b000, .funct7 = 0b0100000 },

.ld => .{ .opcode = 0b0000011, .funct3 = 0b011, .funct7 = null },
Expand Down Expand Up @@ -84,7 +87,6 @@ pub const Mnemonic = enum {
.beq => .{ .opcode = 0b1100011, .funct3 = 0b000, .funct7 = null },

.slt => .{ .opcode = 0b0110011, .funct3 = 0b010, .funct7 = 0b0000000 },
.sltu => .{ .opcode = 0b0110011, .funct3 = 0b011, .funct7 = 0b0000000 },

.xor => .{ .opcode = 0b0110011, .funct3 = 0b100, .funct7 = 0b0000000 },

Expand Down Expand Up @@ -149,6 +151,7 @@ pub const InstEnc = enum {
.xor,
.add,
.sub,
.@"and",
=> .R,

.ecall,
Expand Down
6 changes: 6 additions & 0 deletions src/arch/riscv64/Mir.zig
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ pub const Inst = struct {
lui,
mv,

@"and",
xor,

ebreak,
ecall,
unimp,
Expand All @@ -49,6 +52,9 @@ pub const Inst = struct {
/// Absolute Value, uses i_type payload.
abs,

sltu,
slt,

/// Immediate Logical Right Shift, uses i_type payload
srli,
/// Immediate Logical Left Shift, uses i_type payload
Expand Down
77 changes: 74 additions & 3 deletions src/arch/riscv64/abi.zig
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const bits = @import("bits.zig");
const Register = bits.Register;
const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;
const Type = @import("../../type.zig").Type;
const InternPool = @import("../../InternPool.zig");
const Module = @import("../../Module.zig");
const assert = std.debug.assert;

Expand Down Expand Up @@ -97,7 +98,10 @@ pub fn classifyType(ty: Type, mod: *Module) Class {
pub fn classifySystem(ty: Type, zcu: *Module) [8]Class {
const ip = zcu.intern_pool;
var result = [1]Class{.none} ** 8;

const memory_class = [_]Class{
.memory, .none, .none, .none,
.none, .none, .none, .none,
};
switch (ty.zigTypeTag(zcu)) {
.Bool, .Void, .NoReturn => {
result[0] = .integer;
Expand Down Expand Up @@ -146,7 +150,12 @@ pub fn classifySystem(ty: Type, zcu: *Module) [8]Class {
// anyerror!void can fit into one register
if (payload_bits == 0) return result;

std.debug.panic("support ErrorUnion payload {}", .{payload_ty.fmt(zcu)});
if (payload_bits <= 64) {
result[1] = .integer;
return result;
}

std.debug.panic("TODO: classifySystem ErrorUnion > 64 bit payload", .{});
},
.Struct => {
const loaded_struct = ip.loadStructType(ty.toIntern());
Expand All @@ -158,13 +167,75 @@ pub fn classifySystem(ty: Type, zcu: *Module) [8]Class {
if (ty_size > 8) result[1] = .integer;
return result;
}
if (ty_size > 64)
return memory_class;

std.debug.panic("support Struct in classifySystem", .{});
var byte_offset: u64 = 0;
classifyStruct(&result, &byte_offset, loaded_struct, zcu);

return result;
},
else => |bad_ty| std.debug.panic("classifySystem {s}", .{@tagName(bad_ty)}),
}
}

fn classifyStruct(
result: *[8]Class,
byte_offset: *u64,
loaded_struct: InternPool.LoadedStructType,
zcu: *Module,
) void {
const ip = &zcu.intern_pool;
var field_it = loaded_struct.iterateRuntimeOrder(ip);

while (field_it.next()) |field_index| {
const field_ty = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]);
const field_align = loaded_struct.fieldAlign(ip, field_index);
byte_offset.* = std.mem.alignForward(
u64,
byte_offset.*,
field_align.toByteUnits() orelse field_ty.abiAlignment(zcu).toByteUnits().?,
);
if (zcu.typeToStruct(field_ty)) |field_loaded_struct| {
if (field_loaded_struct.layout != .@"packed") {
classifyStruct(result, byte_offset, field_loaded_struct, zcu);
continue;
}
}
const field_class = std.mem.sliceTo(&classifySystem(field_ty, zcu), .none);
const field_size = field_ty.abiSize(zcu);

combine: {
const result_class = &result[@intCast(byte_offset.* / 8)];
if (result_class.* == field_class[0]) {
break :combine;
}

if (result_class.* == .none) {
result_class.* = field_class[0];
break :combine;
}
assert(field_class[0] != .none);

// "If one of the classes is MEMORY, the result is the MEMORY class."
if (result_class.* == .memory or field_class[0] == .memory) {
result_class.* = .memory;
break :combine;
}

// "If one of the classes is INTEGER, the result is the INTEGER."
if (result_class.* == .integer or field_class[0] == .integer) {
result_class.* = .integer;
break :combine;
}

result_class.* = .integer;
}
@memcpy(result[@intCast(byte_offset.* / 8 + 1)..][0 .. field_class.len - 1], field_class[1..]);
byte_offset.* += field_size;
}
}

pub const callee_preserved_regs = [_]Register{
// .s0 is ommited to be used as a frame pointer
.s1, .s2, .s3, .s4, .s5, .s6, .s7, .s8, .s9, .s10, .s11,
Expand Down
1 change: 0 additions & 1 deletion test/behavior/array.zig
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@ test "array concat with tuple" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;

const array: [2]u8 = .{ 1, 2 };
{
Expand Down
1 change: 0 additions & 1 deletion test/behavior/basic.zig
Original file line number Diff line number Diff line change
Expand Up @@ -593,7 +593,6 @@ test "equality compare fn ptrs" {

test "self reference through fn ptr field" {
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;

const S = struct {
const A = struct {
Expand Down
2 changes: 0 additions & 2 deletions test/behavior/cast.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2073,7 +2073,6 @@ test "peer type resolution: empty tuple pointer and slice" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;

var a: [:0]const u8 = "Hello";
var b = &.{};
Expand All @@ -2095,7 +2094,6 @@ test "peer type resolution: tuple pointer and slice" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;

var a: [:0]const u8 = "Hello";
var b = &.{ @as(u8, 'x'), @as(u8, 'y'), @as(u8, 'z') };
Expand Down
3 changes: 0 additions & 3 deletions test/behavior/fn.zig
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,6 @@ test "function with complex callconv and return type expressions" {

test "pass by non-copying value" {
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;

try expect(addPointCoords(Point{ .x = 1, .y = 2 }) == 3);
}
Expand Down Expand Up @@ -219,7 +218,6 @@ fn addPointCoordsVar(pt: anytype) !i32 {

test "pass by non-copying value as method" {
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;

var pt = Point2{ .x = 1, .y = 2 };
try expect(pt.addPointCoords() == 3);
Expand All @@ -236,7 +234,6 @@ const Point2 = struct {

test "pass by non-copying value as method, which is generic" {
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;

var pt = Point3{ .x = 1, .y = 2 };
try expect(pt.addPointCoords(i32) == 3);
Expand Down
1 change: 0 additions & 1 deletion test/behavior/fn_delegation.zig
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ fn custom(comptime T: type, comptime num: u64) fn (T) u64 {
test "fn delegation" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;

const foo = Foo{};
try expect(foo.one() == 11);
Expand Down
1 change: 0 additions & 1 deletion test/behavior/generics.zig
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,6 @@ test "extern function used as generic parameter" {

test "generic struct as parameter type" {
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;

const S = struct {
fn doTheTest(comptime Int: type, thing: struct { int: Int }) !void {
Expand Down
1 change: 0 additions & 1 deletion test/behavior/pointers.zig
Original file line number Diff line number Diff line change
Expand Up @@ -434,7 +434,6 @@ test "indexing array with sentinel returns correct type" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;

var s: [:0]const u8 = "abc";
try testing.expectEqualSlices(u8, "*const u8", @typeName(@TypeOf(&s[0])));
Expand Down
1 change: 0 additions & 1 deletion test/behavior/sizeof_and_typeof.zig
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,6 @@ test "Extern function calls, dereferences and field access in @TypeOf" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;

const Test = struct {
fn test_fn_1(a: c_long) @TypeOf(c_fopen("test", "r").*) {
Expand Down
1 change: 0 additions & 1 deletion test/behavior/slice.zig
Original file line number Diff line number Diff line change
Expand Up @@ -939,7 +939,6 @@ test "modify slice length at comptime" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;

const arr: [2]u8 = .{ 10, 20 };
comptime var s: []const u8 = arr[0..0];
Expand Down
Loading

0 comments on commit 2fd83d8

Please sign in to comment.