Commit b2150094ba
Changed files (3)
src
arch
riscv64
src/arch/riscv64/CodeGen.zig
@@ -928,6 +928,8 @@ fn binOpRegister(
.sub => .sub,
.cmp_eq => .cmp_eq,
.cmp_gt => .cmp_gt,
+ .shl => .sllw,
+ .shr => .srlw,
else => return self.fail("TODO: binOpRegister {s}", .{@tagName(tag)}),
};
@@ -947,6 +949,84 @@ fn binOpRegister(
return MCValue{ .register = dest_reg };
}
+/// Don't call this function directly. Use binOp instead.
+///
+/// Call this function if rhs is an immediate. Generates I version of binops.
+///
+/// Asserts that rhs is an immediate MCValue
+fn binOpImm(
+ self: *Self,
+ tag: Air.Inst.Tag,
+ maybe_inst: ?Air.Inst.Index,
+ lhs: MCValue,
+ rhs: MCValue,
+ lhs_ty: Type,
+ rhs_ty: Type,
+) !MCValue {
+ _ = rhs_ty;
+ assert(rhs == .immediate);
+
+ const lhs_is_register = lhs == .register;
+
+ const lhs_lock: ?RegisterLock = if (lhs_is_register)
+ self.register_manager.lockReg(lhs.register)
+ else
+ null;
+ defer if (lhs_lock) |reg| self.register_manager.unlockReg(reg);
+
+ const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
+
+ const lhs_reg = if (lhs_is_register) lhs.register else blk: {
+ const track_inst: ?Air.Inst.Index = if (maybe_inst) |inst| inst: {
+ const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
+ break :inst bin_op.lhs.toIndex().?;
+ } else null;
+
+ const reg = try self.register_manager.allocReg(track_inst, gp);
+
+ if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
+
+ break :blk reg;
+ };
+ const new_lhs_lock = self.register_manager.lockReg(lhs_reg);
+ defer if (new_lhs_lock) |reg| self.register_manager.unlockReg(reg);
+
+ const dest_reg = if (maybe_inst) |inst| blk: {
+ const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
+
+ if (lhs_is_register and self.reuseOperand(inst, bin_op.lhs, 0, lhs)) {
+ break :blk lhs_reg;
+ } else {
+ break :blk try self.register_manager.allocReg(inst, gp);
+ }
+ } else try self.register_manager.allocReg(null, gp);
+
+ if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs);
+
+ const mir_tag: Mir.Inst.Tag = switch (tag) {
+ .shl => .slli,
+ .shr => .srli,
+ else => return self.fail("TODO: binOpImm {s}", .{@tagName(tag)}),
+ };
+
+ _ = try self.addInst(.{
+ .tag = mir_tag,
+ .data = .{
+ .i_type = .{
+ .rd = dest_reg,
+ .rs1 = lhs_reg,
+ .imm12 = math.cast(i12, rhs.immediate) orelse {
+ return self.fail("TODO: binOpImm larger than i12 i_type payload", .{});
+ },
+ },
+ },
+ });
+
+ // generate the struct for OF checks
+
+ return MCValue{ .register = dest_reg };
+}
+
/// For all your binary operation needs, this function will generate
/// the corresponding Mir instruction(s). Returns the location of the
/// result.
@@ -989,8 +1069,10 @@ fn binOp(
assert(lhs_ty.eql(rhs_ty, mod));
const int_info = lhs_ty.intInfo(mod);
if (int_info.bits <= 64) {
- // TODO immediate operands
- return try self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
+ if (rhs == .immediate) {
+ return self.binOpImm(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
+ }
+ return self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
} else {
return self.fail("TODO binary operations on int with bits > 64", .{});
}
@@ -1025,6 +1107,28 @@ fn binOp(
else => unreachable,
}
},
+
+ // These instructions have unsymteric bit sizes.
+ .shr,
+ .shl,
+ => {
+ switch (lhs_ty.zigTypeTag(mod)) {
+ .Float => return self.fail("TODO binary operations on floats", .{}),
+ .Vector => return self.fail("TODO binary operations on vectors", .{}),
+ .Int => {
+ const int_info = lhs_ty.intInfo(mod);
+ if (int_info.bits <= 64) {
+ if (rhs == .immediate) {
+ return self.binOpImm(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
+ }
+ return self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
+ } else {
+ return self.fail("TODO binary operations on int with bits > 64", .{});
+ }
+ },
+ else => unreachable,
+ }
+ },
else => unreachable,
}
}
@@ -1163,7 +1267,13 @@ fn airXor(self: *Self, inst: Air.Inst.Index) !void {
fn airShl(self: *Self, inst: Air.Inst.Index) !void {
const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
- const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement shl for {}", .{self.target.cpu.arch});
+ const result: MCValue = if (self.liveness.isUnused(inst)) .dead 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);
+ break :result try self.binOp(.shl, inst, lhs, rhs, lhs_ty, rhs_ty);
+ };
return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
}
@@ -1426,7 +1536,11 @@ fn airAbs(self: *Self, inst: Air.Inst.Index) !void {
fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void {
const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
- const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airByteSwap for {}", .{self.target.cpu.arch});
+ const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
+ if (true)
+ return self.fail("TODO: airByteSwap", .{});
+ break :result undefined;
+ };
return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
}
src/arch/riscv64/Emit.zig
@@ -98,7 +98,11 @@ pub fn emitMir(
.sh => try emit.mirIType(inst),
.sb => try emit.mirIType(inst),
+ .srlw => try emit.mirRType(inst),
+ .sllw => try emit.mirRType(inst),
+
.srli => try emit.mirIType(inst),
+ .slli => try emit.mirIType(inst),
.ldr_ptr_stack => try emit.mirIType(inst),
@@ -173,14 +177,20 @@ fn mirRType(emit: *Emit, inst: Mir.Inst.Index) !void {
const tag = emit.mir.instructions.items(.tag)[inst];
const r_type = emit.mir.instructions.items(.data)[inst].r_type;
+ const rd = r_type.rd;
+ const rs1 = r_type.rs1;
+ const rs2 = r_type.rs2;
+
switch (tag) {
- .add => try emit.writeInstruction(Instruction.add(r_type.rd, r_type.rs1, r_type.rs2)),
- .sub => try emit.writeInstruction(Instruction.sub(r_type.rd, r_type.rs1, r_type.rs2)),
- .cmp_gt => try emit.writeInstruction(Instruction.slt(r_type.rd, r_type.rs1, r_type.rs2)),
+ .add => try emit.writeInstruction(Instruction.add(rd, rs1, rs2)),
+ .sub => try emit.writeInstruction(Instruction.sub(rd, rs1, rs2)),
+ .cmp_gt => try emit.writeInstruction(Instruction.slt(rd, rs1, rs2)),
.cmp_eq => {
- try emit.writeInstruction(Instruction.xor(r_type.rd, r_type.rs1, r_type.rs2));
- try emit.writeInstruction(Instruction.sltiu(r_type.rd, r_type.rd, 1));
+ try emit.writeInstruction(Instruction.xor(rd, rs1, rs2));
+ try emit.writeInstruction(Instruction.sltiu(rd, rd, 1));
},
+ .sllw => try emit.writeInstruction(Instruction.sllw(rd, rs1, rs2)),
+ .srlw => try emit.writeInstruction(Instruction.srlw(rd, rs1, rs2)),
else => unreachable,
}
}
@@ -231,6 +241,7 @@ fn mirIType(emit: *Emit, inst: Mir.Inst.Index) !void {
},
.srli => try emit.writeInstruction(Instruction.srli(i_type.rd, i_type.rs1, @intCast(i_type.imm12))),
+ .slli => try emit.writeInstruction(Instruction.slli(i_type.rd, i_type.rs1, @intCast(i_type.imm12))),
else => unreachable,
}
src/arch/riscv64/Mir.zig
@@ -41,8 +41,14 @@ pub const Inst = struct {
/// Absolute Value, uses i_type payload.
abs,
- /// Logical Right Shift, uses i_type payload
+ /// Immediate Logical Right Shift, uses i_type payload
srli,
+ /// Immediate Logical Left Shift, uses i_type payload
+ slli,
+ /// Register Logical Left Shift, uses r_type payload
+ sllw,
+ /// Register Logical Right Shit, uses r_type payload
+ srlw,
jal,
/// Jumps. Uses `inst` payload.