aboutsummaryrefslogtreecommitdiff
path: root/src/codegen/llvm.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/codegen/llvm.zig')
-rw-r--r--src/codegen/llvm.zig36
1 files changed, 36 insertions, 0 deletions
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;