mirror of
https://github.com/ziglang/zig.git
synced 2026-02-21 16:54:52 +00:00
riscv: implement basic logical shifting
This commit is contained in:
parent
664e3e16fa
commit
b2150094ba
@ -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 });
|
||||
}
|
||||
|
||||
|
||||
@ -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,
|
||||
}
|
||||
|
||||
@ -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.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user