diff options
| author | Koakuma <koachan@protonmail.com> | 2022-04-10 11:06:29 +0700 |
|---|---|---|
| committer | Koakuma <koachan@protonmail.com> | 2022-04-14 22:18:06 +0700 |
| commit | 5e2045cbe549c9020ebbbecc763699fc4a68c818 (patch) | |
| tree | 41740ad177f355899d1517bbc8f549b5805c676a /src | |
| parent | 42f4bd34216ae1ae03df0a56502919109e030136 (diff) | |
| download | zig-5e2045cbe549c9020ebbbecc763699fc4a68c818.tar.gz zig-5e2045cbe549c9020ebbbecc763699fc4a68c818.zip | |
stage2: sparcv9: Implement basic asm codegen
Diffstat (limited to 'src')
| -rw-r--r-- | src/arch/sparcv9/CodeGen.zig | 122 |
1 files changed, 113 insertions, 9 deletions
diff --git a/src/arch/sparcv9/CodeGen.zig b/src/arch/sparcv9/CodeGen.zig index 7d0a178f9b..7ff1473921 100644 --- a/src/arch/sparcv9/CodeGen.zig +++ b/src/arch/sparcv9/CodeGen.zig @@ -521,8 +521,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { => try self.airDbgBlock(inst), .call => try self.airCall(inst, .auto), - .call_always_tail => @panic("TODO try self.airCall(inst, .always_tail)"), - .call_never_tail => @panic("TODO try self.airCall(inst, .never_tail)"), + .call_always_tail => try self.airCall(inst, .always_tail), + .call_never_tail => try self.airCall(inst, .never_tail), .call_never_inline => try self.airCall(inst, .never_inline), .atomic_store_unordered => @panic("TODO try self.airAtomicStore(inst, .Unordered)"), @@ -586,16 +586,106 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { const is_volatile = (extra.data.flags & 0x80000000) != 0; const clobbers_len = @truncate(u31, extra.data.flags); var extra_i: usize = extra.end; - const outputs = @bitCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.outputs_len]); + const outputs = @bitCast([]const Air.Inst.Ref, self.air.extra[extra_i..extra_i+extra.data.outputs_len]); extra_i += outputs.len; - const inputs = @bitCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.inputs_len]); + const inputs = @bitCast([]const Air.Inst.Ref, self.air.extra[extra_i..extra_i+extra.data.inputs_len]); extra_i += inputs.len; const dead = !is_volatile and self.liveness.isUnused(inst); - _ = dead; - _ = clobbers_len; + const result: MCValue = if (dead) .dead else result: { + if (outputs.len > 1) { + return self.fail("TODO implement codegen for asm with more than 1 output", .{}); + } + + const output_constraint: ?[]const u8 = for (outputs) |output| { + if (output != .none) { + return self.fail("TODO implement codegen for non-expr asm", .{}); + } + const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0); + // This equation accounts for the fact that even if we have exactly 4 bytes + // for the string, we still use the next u32 for the null terminator. + extra_i += constraint.len / 4 + 1; + + break constraint; + } else null; + + for (inputs) |input| { + const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0); + // This equation accounts for the fact that even if we have exactly 4 bytes + // for the string, we still use the next u32 for the null terminator. + extra_i += constraint.len / 4 + 1; + + if (constraint.len < 3 or constraint[0] != '{' or constraint[constraint.len - 1] != '}') { + return self.fail("unrecognized asm input constraint: '{s}'", .{constraint}); + } + const reg_name = constraint[1 .. constraint.len - 1]; + const reg = parseRegName(reg_name) orelse + return self.fail("unrecognized register: '{s}'", .{reg_name}); + + const arg_mcv = try self.resolveInst(input); + try self.register_manager.getReg(reg, null); + try self.genSetReg(self.air.typeOf(input), reg, arg_mcv); + } + + { + var clobber_i: u32 = 0; + while (clobber_i < clobbers_len) : (clobber_i += 1) { + const clobber = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0); + // This equation accounts for the fact that even if we have exactly 4 bytes + // for the string, we still use the next u32 for the null terminator. + extra_i += clobber.len / 4 + 1; + + // TODO honor these + } + } + + const asm_source = std.mem.sliceAsBytes(self.air.extra[extra_i..])[0..extra.data.source_len]; + + if (mem.eql(u8, asm_source, "ta 0x6d")) { + _ = try self.addInst(.{ + .tag = .tcc, + .data = .{ + .trap = .{ + .is_imm = true, + .cond = 0b1000, // TODO need to look into changing this into an enum + .rs2_or_imm = .{ .imm = 0x6d }, + }, + }, + }); + } else { + return self.fail("TODO implement a full SPARCv9 assembly parsing", .{}); + } + + if (output_constraint) |output| { + if (output.len < 4 or output[0] != '=' or output[1] != '{' or output[output.len - 1] != '}') { + return self.fail("unrecognized asm output constraint: '{s}'", .{output}); + } + const reg_name = output[2 .. output.len - 1]; + const reg = parseRegName(reg_name) orelse + return self.fail("unrecognized register: '{s}'", .{reg_name}); + break :result MCValue{ .register = reg }; + } else { + break :result MCValue{ .none = {} }; + } + }; + + simple: { + var buf = [1]Air.Inst.Ref{.none} ** (Liveness.bpi - 1); + var buf_index: usize = 0; + for (outputs) |output| { + if (output == .none) continue; - return self.fail("TODO implement asm for {}", .{self.target.cpu.arch}); + if (buf_index >= buf.len) break :simple; + buf[buf_index] = output; + buf_index += 1; + } + if (buf_index + inputs.len > buf.len) break :simple; + std.mem.copy(Air.Inst.Ref, buf[buf_index..], inputs); + return self.finishAir(inst, result, buf); + } + + @panic("TODO implement asm return"); + //return self.fail("TODO implement asm return for {}", .{self.target.cpu.arch}); } fn airArg(self: *Self, inst: Air.Inst.Index) !void { @@ -759,9 +849,16 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. }); } - // TODO handle return value + const result = info.return_value; + + if (args.len + 1 <= Liveness.bpi - 1) { + var buf = [1]Air.Inst.Ref{.none} ** (Liveness.bpi - 1); + buf[0] = callee; + std.mem.copy(Air.Inst.Ref, buf[1..], args); + return self.finishAir(inst, result, buf); + } - return self.fail("TODO implement call for {}", .{self.target.cpu.arch}); + @panic("TODO handle return value with BigTomb"); } fn airDbgBlock(self: *Self, inst: Air.Inst.Index) !void { @@ -1218,6 +1315,13 @@ fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue { } } +fn parseRegName(name: []const u8) ?Register { + if (@hasDecl(Register, "parseRegName")) { + return Register.parseRegName(name); + } + return std.meta.stringToEnum(Register, name); +} + fn performReloc(self: *Self, inst: Mir.Inst.Index) !void { const tag = self.mir_instructions.items(.tag)[inst]; switch (tag) { |
