aboutsummaryrefslogtreecommitdiff
path: root/src/codegen.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/codegen.zig')
-rw-r--r--src/codegen.zig36
1 files changed, 26 insertions, 10 deletions
diff --git a/src/codegen.zig b/src/codegen.zig
index b0bf5c5..368309c 100644
--- a/src/codegen.zig
+++ b/src/codegen.zig
@@ -485,20 +485,36 @@ const Context = struct {
}
}
- fn genConstant(self: *Context, constant: compile.Instr.Constant) !void {
- const reg = self.register_allocator.allocate(constant.dest) orelse return error.OutOfRegisters;
-
- if (constant.value <= std.math.maxInt(i12)) {
- try self.emit(.addi(reg, .zero, @intCast(constant.value)));
- } else if (constant.value <= std.math.maxInt(i32)) {
- // If the higest bit in the immediate in addi is set, it will be sign extended. We negate that by adding one more to the immediate for lui.
- try self.emit(.lui(reg, @intCast((constant.value >> 12) + if (constant.value & (1 << 11) != 0) @as(u64, 1) else 0)));
- try self.emit(.addi(reg, reg, @bitCast(@as(u12, @truncate(constant.value)))));
+ fn genConstantInner(self: *Context, reg: Register, value: u64) !void {
+ if (value <= std.math.maxInt(i12)) {
+ // If the highest bit is set, we will get sign extension from this, but it will be
+ // cleared by the next addiw.
+ try self.emit(Instruction.addi(reg, .zero, @intCast(value)));
+ } else if (value <= std.math.maxInt(i32)) {
+ const lower: u12 = @truncate(value);
+ const upper: u20 = @truncate(if (lower >> 11 == 1) (value >> 12) + 1 else value >> 12);
+ // If the highest bit in upper is set here, we will get an unwanted sign extension, but
+ // that will be cleared in the `addiw` right afterwards. If the highest bit was set,
+ // then that must be because (lower >> 11 == 1) happened, so lower is not zero, thus the
+ // `addiw` is guaranteed to be run. The only other way the highest bit can be set would
+ // be if value had `1 << 32 == 1`, but then it would not be smaller than
+ // `std.math.maxInt(i32)`.
+ try self.emit(.lui(reg, @bitCast(upper)));
+ if (lower > 0) try self.emit(.addiw(reg, reg, @bitCast(lower)));
} else {
- unreachable; // TODO
+ const thisVal: u12 = @truncate(value);
+ const nextVal = if (thisVal >> 11 == 1) (value >> 12) + 1 else value >> 12;
+ try self.genConstantInner(reg, nextVal);
+ try self.emit(.slli(reg, reg, 12)); // TODO: sometimes these `slli`s can be collapsed
+ if (thisVal > 0) try self.emit(.addi(reg, reg, @bitCast(thisVal)));
}
}
+ fn genConstant(self: *Context, constant: compile.Instr.Constant) !void {
+ const reg = self.register_allocator.allocate(constant.dest) orelse return error.OutOfRegisters;
+ try self.genConstantInner(reg, constant.value);
+ }
+
fn genBinOp(self: *Context, bin_op: compile.Instr.BinOp) !void {
const lhs = self.register_allocator.get(bin_op.lhs);
const rhs = self.register_allocator.get(bin_op.rhs);