aboutsummaryrefslogtreecommitdiff
path: root/src/codegen
diff options
context:
space:
mode:
authorRobin Voetter <robin@voetter.nl>2021-12-21 01:38:46 +0100
committerRobin Voetter <robin@voetter.nl>2021-12-21 01:47:27 +0100
commite106e18d96595bdc4bc037e0b36900992a576160 (patch)
tree950e169ddf58e761fb7b90fa4580cc26ef045cbf /src/codegen
parent964dbeb82623515b8392c8c7cb9317246812174e (diff)
downloadzig-e106e18d96595bdc4bc037e0b36900992a576160.tar.gz
zig-e106e18d96595bdc4bc037e0b36900992a576160.zip
stage2: @shlWithOverflow
Diffstat (limited to 'src/codegen')
-rw-r--r--src/codegen/c.zig7
-rw-r--r--src/codegen/llvm.zig36
2 files changed, 43 insertions, 0 deletions
diff --git a/src/codegen/c.zig b/src/codegen/c.zig
index 68b700db17..12ce813a0f 100644
--- a/src/codegen/c.zig
+++ b/src/codegen/c.zig
@@ -1159,6 +1159,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
.add_with_overflow => try airAddWithOverflow(f, inst),
.sub_with_overflow => try airSubWithOverflow(f, inst),
.mul_with_overflow => try airMulWithOverflow(f, inst),
+ .shl_with_overflow => try airShlWithOverflow(f, inst),
.min => try airMinMax(f, inst, "<"),
.max => try airMinMax(f, inst, ">"),
@@ -1887,6 +1888,12 @@ fn airMulWithOverflow(f: *Function, inst: Air.Inst.Index) !CValue {
return f.fail("TODO mul with overflow", .{});
}
+fn airShlWithOverflow(f: *Function, inst: Air.Inst.Index) !CValue {
+ _ = f;
+ _ = inst;
+ return f.fail("TODO shl with overflow", .{});
+}
+
fn airNot(f: *Function, inst: Air.Inst.Index) !CValue {
if (f.liveness.isUnused(inst))
return CValue.none;
diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig
index 4089a39cb3..78848bee28 100644
--- a/src/codegen/llvm.zig
+++ b/src/codegen/llvm.zig
@@ -1721,6 +1721,7 @@ pub const FuncGen = struct {
.add_with_overflow => try self.airOverflow(inst, "llvm.sadd.with.overflow", "llvm.uadd.with.overflow"),
.sub_with_overflow => try self.airOverflow(inst, "llvm.ssub.with.overflow", "llvm.usub.with.overflow"),
.mul_with_overflow => try self.airOverflow(inst, "llvm.smul.with.overflow", "llvm.umul.with.overflow"),
+ .shl_with_overflow => try self.airShlWithOverflow(inst),
.bit_and, .bool_and => try self.airAnd(inst),
.bit_or, .bool_or => try self.airOr(inst),
@@ -3176,6 +3177,41 @@ pub const FuncGen = struct {
return overflow_bit;
}
+ fn airShlWithOverflow(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
+ if (self.liveness.isUnused(inst))
+ return null;
+
+ const pl_op = self.air.instructions.items(.data)[inst].pl_op;
+ const extra = self.air.extraData(Air.Bin, pl_op.payload).data;
+
+ const ptr = try self.resolveInst(pl_op.operand);
+ const lhs = try self.resolveInst(extra.lhs);
+ const rhs = try self.resolveInst(extra.rhs);
+
+ const ptr_ty = self.air.typeOf(pl_op.operand);
+ const lhs_ty = self.air.typeOf(extra.lhs);
+ const rhs_ty = self.air.typeOf(extra.rhs);
+
+ const tg = self.dg.module.getTarget();
+
+ const casted_rhs = if (rhs_ty.bitSize(tg) < lhs_ty.bitSize(tg))
+ self.builder.buildZExt(rhs, try self.dg.llvmType(lhs_ty), "")
+ else
+ rhs;
+
+ const result = self.builder.buildShl(lhs, casted_rhs, "");
+ const reconstructed = if (lhs_ty.isSignedInt())
+ self.builder.buildAShr(result, casted_rhs, "")
+ else
+ self.builder.buildLShr(result, casted_rhs, "");
+
+ const overflow_bit = self.builder.buildICmp(.NE, lhs, reconstructed, "");
+
+ self.store(ptr, ptr_ty, result, .NotAtomic);
+
+ return overflow_bit;
+ }
+
fn airAnd(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
if (self.liveness.isUnused(inst))
return null;