mirror of
https://github.com/ziglang/zig.git
synced 2026-01-04 04:25:05 +00:00
SPU-II: Implement function calls
This commit is contained in:
parent
d005ff16c6
commit
cdefc6acba
@ -102,6 +102,7 @@ pub fn generateSymbol(
|
||||
//.sparcv9 => return Function(.sparcv9).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
|
||||
//.sparcel => return Function(.sparcel).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
|
||||
//.s390x => return Function(.s390x).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
|
||||
.spu_2 => return Function(.spu_2).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
|
||||
//.tce => return Function(.tce).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
|
||||
//.tcele => return Function(.tcele).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
|
||||
//.thumb => return Function(.thumb).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
|
||||
@ -1349,6 +1350,44 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
||||
return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{});
|
||||
}
|
||||
},
|
||||
.spu_2 => {
|
||||
if (inst.func.cast(ir.Inst.Constant)) |func_inst| {
|
||||
if (info.args.len != 0) {
|
||||
return self.fail(inst.base.src, "TODO implement call with more than 0 parameters", .{});
|
||||
}
|
||||
if (func_inst.val.cast(Value.Payload.Function)) |func_val| {
|
||||
const func = func_val.func;
|
||||
const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
|
||||
const got_addr = @intCast(u16, got.p_vaddr + func.owner_decl.link.elf.offset_table_index * 2);
|
||||
const return_type = func.owner_decl.typed_value.most_recent.typed_value.ty.fnReturnType();
|
||||
// First, push the return address, then jump; if noreturn, don't bother with the first step
|
||||
// TODO: implement packed struct -> u16 at comptime and move the bitcast here
|
||||
var instr = Instruction{ .condition = .always, .input0 = .immediate, .input1 = .zero, .modify_flags = false, .output = .jump, .command = .load16 };
|
||||
if (return_type.zigTypeTag() == .NoReturn) {
|
||||
try self.code.resize(self.code.items.len + 4);
|
||||
mem.writeIntLittle(u16, self.code.items[self.code.items.len - 4 ..][0..2], @bitCast(u16, instr));
|
||||
mem.writeIntLittle(u16, self.code.items[self.code.items.len - 2 ..][0..2], got_addr);
|
||||
return MCValue.unreach;
|
||||
} else {
|
||||
try self.code.resize(self.code.items.len + 8);
|
||||
var push = Instruction{ .condition = .always, .input0 = .immediate, .input1 = .zero, .modify_flags = false, .output = .push, .command = .ipget };
|
||||
mem.writeIntLittle(u16, self.code.items[self.code.items.len - 8 ..][0..2], @bitCast(u16, push));
|
||||
mem.writeIntLittle(u16, self.code.items[self.code.items.len - 6 ..][0..2], @as(u16, 4));
|
||||
mem.writeIntLittle(u16, self.code.items[self.code.items.len - 4 ..][0..2], @bitCast(u16, instr));
|
||||
mem.writeIntLittle(u16, self.code.items[self.code.items.len - 2 ..][0..2], got_addr);
|
||||
switch (return_type.zigTypeTag()) {
|
||||
.Void => return MCValue{ .none = {} },
|
||||
.NoReturn => unreachable,
|
||||
else => return self.fail(inst.base.src, "TODO implement fn call with non-void return value", .{}),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{});
|
||||
}
|
||||
} else {
|
||||
return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{});
|
||||
}
|
||||
},
|
||||
else => return self.fail(inst.base.src, "TODO implement call for {}", .{self.target.cpu.arch}),
|
||||
}
|
||||
} else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
|
||||
@ -1647,19 +1686,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
||||
return self.fail(inst.base.src, "TODO implement inline asm inputs / outputs for SPU Mark II", .{});
|
||||
}
|
||||
if (mem.eql(u8, inst.asm_source, "undefined0")) {
|
||||
// Instructions are 16-bits, plus up to two sixteen bit immediates.
|
||||
// Upper three bits of first byte are the execution
|
||||
// condition; for now, only always (0b000) is supported.
|
||||
// Next, there are two two-bit sequences indicating inputs;
|
||||
// we only care to use zero (0b00).
|
||||
// The lowest bit of byte one indicates whether flags
|
||||
// should be updated; TODO: support that somehow.
|
||||
// In all, we use a zero byte for the first half of the
|
||||
// instruction.
|
||||
// The second byte is 0bOOCCCCCR; OO is output behavior (we
|
||||
// use zero, which discards the output), CCCCC is the
|
||||
// command (8 for undefined0), R is reserved.
|
||||
try self.code.appendSlice(&[_]u8{ 0x00, 0b00010000 });
|
||||
try self.code.resize(self.code.items.len + 2);
|
||||
var instr = Instruction{ .condition = .always, .input0 = .zero, .input1 = .zero, .modify_flags = false, .output = .discard, .command = .undefined0 };
|
||||
mem.writeIntLittle(u16, self.code.items[self.code.items.len - 2 ..][0..2], @bitCast(u16, instr));
|
||||
return MCValue.none;
|
||||
} else {
|
||||
return self.fail(inst.base.src, "TODO implement support for more SPU II assembly instructions", .{});
|
||||
@ -1742,6 +1771,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
||||
/// X => extension to the SIB.index field
|
||||
/// B => extension to the MODRM.rm field or the SIB.base field
|
||||
fn rex(self: *Self, arg: struct { b: bool = false, w: bool = false, x: bool = false, r: bool = false }) void {
|
||||
std.debug.assert(arch == .x86_64);
|
||||
// From section 2.2.1.2 of the manual, REX is encoded as b0100WRXB.
|
||||
var value: u8 = 0x40;
|
||||
if (arg.b) {
|
||||
@ -2289,7 +2319,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
||||
result.stack_byte_count = next_stack_offset;
|
||||
result.stack_align = 16;
|
||||
},
|
||||
else => return self.fail(src, "TODO implement function parameters for {}", .{cc}),
|
||||
else => return self.fail(src, "TODO implement function parameters for {} on x86_64", .{cc}),
|
||||
}
|
||||
},
|
||||
else => if (param_types.len != 0)
|
||||
@ -2336,6 +2366,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
||||
.i386 => @import("codegen/x86.zig"),
|
||||
.x86_64 => @import("codegen/x86_64.zig"),
|
||||
.riscv64 => @import("codegen/riscv64.zig"),
|
||||
.spu_2 => @import("codegen/spu-mk2.zig"),
|
||||
else => struct {
|
||||
pub const Register = enum {
|
||||
dummy,
|
||||
|
||||
167
src-self-hosted/codegen/spu-mk2.zig
Normal file
167
src-self-hosted/codegen/spu-mk2.zig
Normal file
@ -0,0 +1,167 @@
|
||||
const std = @import("std");
|
||||
|
||||
pub const ExecutionCondition = enum(u3) {
|
||||
always = 0,
|
||||
when_zero = 1,
|
||||
not_zero = 2,
|
||||
greater_zero = 3,
|
||||
less_than_zero = 4,
|
||||
greater_or_equal_zero = 5,
|
||||
less_or_equal_zero = 6,
|
||||
overflow = 7,
|
||||
};
|
||||
|
||||
pub const InputBehaviour = enum(u2) {
|
||||
zero = 0,
|
||||
immediate = 1,
|
||||
peek = 2,
|
||||
pop = 3,
|
||||
};
|
||||
|
||||
pub const OutputBehaviour = enum(u2) {
|
||||
discard = 0,
|
||||
push = 1,
|
||||
jump = 2,
|
||||
jump_relative = 3,
|
||||
};
|
||||
|
||||
pub const Command = enum(u5) {
|
||||
copy = 0,
|
||||
ipget = 1,
|
||||
get = 2,
|
||||
set = 3,
|
||||
store8 = 4,
|
||||
store16 = 5,
|
||||
load8 = 6,
|
||||
load16 = 7,
|
||||
undefined0 = 8,
|
||||
undefined1 = 9,
|
||||
frget = 10,
|
||||
frset = 11,
|
||||
bpget = 12,
|
||||
bpset = 13,
|
||||
spget = 14,
|
||||
spset = 15,
|
||||
add = 16,
|
||||
sub = 17,
|
||||
mul = 18,
|
||||
div = 19,
|
||||
mod = 20,
|
||||
@"and" = 21,
|
||||
@"or" = 22,
|
||||
xor = 23,
|
||||
not = 24,
|
||||
signext = 25,
|
||||
rol = 26,
|
||||
ror = 27,
|
||||
bswap = 28,
|
||||
asr = 29,
|
||||
lsl = 30,
|
||||
lsr = 31,
|
||||
};
|
||||
|
||||
pub const Instruction = packed struct {
|
||||
condition: ExecutionCondition,
|
||||
input0: InputBehaviour,
|
||||
input1: InputBehaviour,
|
||||
modify_flags: bool,
|
||||
output: OutputBehaviour,
|
||||
command: Command,
|
||||
reserved: u1 = 0,
|
||||
|
||||
pub fn format(instr: Instruction, comptime fmt: []const u8, options: std.fmt.FormatOptions, out: anytype) !void {
|
||||
try std.fmt.format(out, "0x{x:0<4} ", .{@bitCast(u16, instr)});
|
||||
try out.writeAll(switch (instr.condition) {
|
||||
.always => " ",
|
||||
.when_zero => "== 0",
|
||||
.not_zero => "!= 0",
|
||||
.greater_zero => " > 0",
|
||||
.less_than_zero => " < 0",
|
||||
.greater_or_equal_zero => ">= 0",
|
||||
.less_or_equal_zero => "<= 0",
|
||||
.overflow => "ovfl",
|
||||
});
|
||||
try out.writeAll(" ");
|
||||
try out.writeAll(switch (instr.input0) {
|
||||
.zero => "zero",
|
||||
.immediate => "imm ",
|
||||
.peek => "peek",
|
||||
.pop => "pop ",
|
||||
});
|
||||
try out.writeAll(" ");
|
||||
try out.writeAll(switch (instr.input1) {
|
||||
.zero => "zero",
|
||||
.immediate => "imm ",
|
||||
.peek => "peek",
|
||||
.pop => "pop ",
|
||||
});
|
||||
try out.writeAll(" ");
|
||||
try out.writeAll(switch (instr.command) {
|
||||
.copy => "copy ",
|
||||
.ipget => "ipget ",
|
||||
.get => "get ",
|
||||
.set => "set ",
|
||||
.store8 => "store8 ",
|
||||
.store16 => "store16 ",
|
||||
.load8 => "load8 ",
|
||||
.load16 => "load16 ",
|
||||
.undefined0 => "undefined",
|
||||
.undefined1 => "undefined",
|
||||
.frget => "frget ",
|
||||
.frset => "frset ",
|
||||
.bpget => "bpget ",
|
||||
.bpset => "bpset ",
|
||||
.spget => "spget ",
|
||||
.spset => "spset ",
|
||||
.add => "add ",
|
||||
.sub => "sub ",
|
||||
.mul => "mul ",
|
||||
.div => "div ",
|
||||
.mod => "mod ",
|
||||
.@"and" => "and ",
|
||||
.@"or" => "or ",
|
||||
.xor => "xor ",
|
||||
.not => "not ",
|
||||
.signext => "signext ",
|
||||
.rol => "rol ",
|
||||
.ror => "ror ",
|
||||
.bswap => "bswap ",
|
||||
.asr => "asr ",
|
||||
.lsl => "lsl ",
|
||||
.lsr => "lsr ",
|
||||
});
|
||||
try out.writeAll(" ");
|
||||
try out.writeAll(switch (instr.output) {
|
||||
.discard => "discard",
|
||||
.push => "push ",
|
||||
.jump => "jmp ",
|
||||
.jump_relative => "rjmp ",
|
||||
});
|
||||
try out.writeAll(" ");
|
||||
try out.writeAll(if (instr.modify_flags)
|
||||
"+ flags"
|
||||
else
|
||||
" ");
|
||||
}
|
||||
};
|
||||
|
||||
pub const FlagRegister = packed struct {
|
||||
zero: bool,
|
||||
negative: bool,
|
||||
carry: bool,
|
||||
carry_enabled: bool,
|
||||
interrupt0_enabled: bool,
|
||||
interrupt1_enabled: bool,
|
||||
interrupt2_enabled: bool,
|
||||
interrupt3_enabled: bool,
|
||||
reserved: u8 = 0,
|
||||
};
|
||||
|
||||
pub const Register = enum {
|
||||
dummy,
|
||||
|
||||
pub fn allocIndex(self: Register) ?u4 {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
pub const callee_preserved_regs = [_]Register{};
|
||||
Loading…
x
Reference in New Issue
Block a user