aboutsummaryrefslogtreecommitdiff
path: root/src/codegen
diff options
context:
space:
mode:
authorTravis Staloch <twostepted@gmail.com>2021-09-02 13:50:24 -0700
committerAndrew Kelley <andrew@ziglang.org>2021-09-28 17:02:43 -0700
commit29f41896ed9d99e82a88f4b63efa182ca0d2f93c (patch)
tree1e6eb1159df89f79b04f050da662653925c77b1c /src/codegen
parent79bc5891c1c4cde0592fe1b10b6c9a85914155cf (diff)
downloadzig-29f41896ed9d99e82a88f4b63efa182ca0d2f93c.tar.gz
zig-29f41896ed9d99e82a88f4b63efa182ca0d2f93c.zip
sat-arithmetic: add operator support
- adds initial support for the operators +|, -|, *|, <<|, +|=, -|=, *|=, <<|= - uses operators in addition to builtins in behavior test - adds binOpExt() and assignBinOpExt() to AstGen.zig. these need to be audited
Diffstat (limited to 'src/codegen')
-rw-r--r--src/codegen/c.zig3
-rw-r--r--src/codegen/llvm.zig66
-rw-r--r--src/codegen/llvm/bindings.zig24
3 files changed, 76 insertions, 17 deletions
diff --git a/src/codegen/c.zig b/src/codegen/c.zig
index 4964f17cd3..dce0c10b4c 100644
--- a/src/codegen/c.zig
+++ b/src/codegen/c.zig
@@ -885,14 +885,17 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
// that wrapping is UB.
.add, .ptr_add => try airBinOp( f, inst, " + "),
.addwrap => try airWrapOp(f, inst, " + ", "addw_"),
+ .addsat => return o.dg.fail("TODO: C backend: implement codegen for addsat", .{}),
// TODO use a different strategy for sub that communicates to the optimizer
// that wrapping is UB.
.sub, .ptr_sub => try airBinOp( f, inst, " - "),
.subwrap => try airWrapOp(f, inst, " - ", "subw_"),
+ .subsat => return o.dg.fail("TODO: C backend: implement codegen for subsat", .{}),
// TODO use a different strategy for mul that communicates to the optimizer
// that wrapping is UB.
.mul => try airBinOp( f, inst, " * "),
.mulwrap => try airWrapOp(f, inst, " * ", "mulw_"),
+ .mulsat => return o.dg.fail("TODO: C backend: implement codegen for mulsat", .{}),
// TODO use a different strategy for div that communicates to the optimizer
// that wrapping is UB.
.div => try airBinOp( f, inst, " / "),
diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig
index f65e0f6d72..c21985d1c5 100644
--- a/src/codegen/llvm.zig
+++ b/src/codegen/llvm.zig
@@ -1236,12 +1236,15 @@ pub const FuncGen = struct {
for (body) |inst| {
const opt_value: ?*const llvm.Value = switch (air_tags[inst]) {
// zig fmt: off
- .add => try self.airAdd(inst, false),
- .addwrap => try self.airAdd(inst, true),
- .sub => try self.airSub(inst, false),
- .subwrap => try self.airSub(inst, true),
- .mul => try self.airMul(inst, false),
- .mulwrap => try self.airMul(inst, true),
+ .add => try self.airAdd(inst, .standard),
+ .addwrap => try self.airAdd(inst, .wrapping),
+ .addsat => try self.airAdd(inst, .saturated),
+ .sub => try self.airSub(inst, .standard),
+ .subwrap => try self.airSub(inst, .wrapping),
+ .subsat => try self.airSub(inst, .saturated),
+ .mul => try self.airMul(inst, .standard),
+ .mulwrap => try self.airMul(inst, .wrapping),
+ .mulsat => try self.airMul(inst, .saturated),
.div => try self.airDiv(inst),
.rem => try self.airRem(inst),
.mod => try self.airMod(inst),
@@ -1252,7 +1255,8 @@ pub const FuncGen = struct {
.bit_or, .bool_or => try self.airOr(inst),
.xor => try self.airXor(inst),
- .shl => try self.airShl(inst),
+ .shl => try self.airShl(inst, false),
+ .shl_sat => try self.airShl(inst, true),
.shr => try self.airShr(inst),
.cmp_eq => try self.airCmp(inst, .eq),
@@ -2024,7 +2028,8 @@ pub const FuncGen = struct {
return self.todo("implement llvm codegen for 'airWrapErrUnionErr'", .{});
}
- fn airAdd(self: *FuncGen, inst: Air.Inst.Index, wrap: bool) !?*const llvm.Value {
+ const ArithmeticType = enum { standard, wrapping, saturated };
+ fn airAdd(self: *FuncGen, inst: Air.Inst.Index, ty: ArithmeticType) !?*const llvm.Value {
if (self.liveness.isUnused(inst))
return null;
@@ -2033,13 +2038,20 @@ pub const FuncGen = struct {
const rhs = try self.resolveInst(bin_op.rhs);
const inst_ty = self.air.typeOfIndex(inst);
- if (inst_ty.isRuntimeFloat()) return self.builder.buildFAdd(lhs, rhs, "");
- if (wrap) return self.builder.buildAdd(lhs, rhs, "");
+ if (inst_ty.isFloat()) return self.builder.buildFAdd(lhs, rhs, "");
+ if (ty == .wrapping)
+ return self.builder.buildAdd(lhs, rhs, "")
+ else if (ty == .saturated) {
+ if (inst_ty.isSignedInt())
+ return self.builder.buildSAddSat(lhs, rhs, "")
+ else
+ return self.builder.buildUAddSat(lhs, rhs, "");
+ }
if (inst_ty.isSignedInt()) return self.builder.buildNSWAdd(lhs, rhs, "");
return self.builder.buildNUWAdd(lhs, rhs, "");
}
- fn airSub(self: *FuncGen, inst: Air.Inst.Index, wrap: bool) !?*const llvm.Value {
+ fn airSub(self: *FuncGen, inst: Air.Inst.Index, ty: ArithmeticType) !?*const llvm.Value {
if (self.liveness.isUnused(inst))
return null;
@@ -2048,13 +2060,20 @@ pub const FuncGen = struct {
const rhs = try self.resolveInst(bin_op.rhs);
const inst_ty = self.air.typeOfIndex(inst);
- if (inst_ty.isRuntimeFloat()) return self.builder.buildFSub(lhs, rhs, "");
- if (wrap) return self.builder.buildSub(lhs, rhs, "");
+ if (inst_ty.isFloat()) return self.builder.buildFSub(lhs, rhs, "");
+ if (ty == .wrapping)
+ return self.builder.buildSub(lhs, rhs, "")
+ else if (ty == .saturated) {
+ if (inst_ty.isSignedInt())
+ return self.builder.buildSSubSat(lhs, rhs, "")
+ else
+ return self.builder.buildUSubSat(lhs, rhs, "");
+ }
if (inst_ty.isSignedInt()) return self.builder.buildNSWSub(lhs, rhs, "");
return self.builder.buildNUWSub(lhs, rhs, "");
}
- fn airMul(self: *FuncGen, inst: Air.Inst.Index, wrap: bool) !?*const llvm.Value {
+ fn airMul(self: *FuncGen, inst: Air.Inst.Index, ty: ArithmeticType) !?*const llvm.Value {
if (self.liveness.isUnused(inst))
return null;
@@ -2063,8 +2082,15 @@ pub const FuncGen = struct {
const rhs = try self.resolveInst(bin_op.rhs);
const inst_ty = self.air.typeOfIndex(inst);
- if (inst_ty.isRuntimeFloat()) return self.builder.buildFMul(lhs, rhs, "");
- if (wrap) return self.builder.buildMul(lhs, rhs, "");
+ if (inst_ty.isFloat()) return self.builder.buildFMul(lhs, rhs, "");
+ if (ty == .wrapping)
+ return self.builder.buildMul(lhs, rhs, "")
+ else if (ty == .saturated) {
+ if (inst_ty.isSignedInt())
+ return self.builder.buildSMulFixSat(lhs, rhs, "")
+ else
+ return self.builder.buildUMulFixSat(lhs, rhs, "");
+ }
if (inst_ty.isSignedInt()) return self.builder.buildNSWMul(lhs, rhs, "");
return self.builder.buildNUWMul(lhs, rhs, "");
}
@@ -2174,7 +2200,7 @@ pub const FuncGen = struct {
return self.builder.buildXor(lhs, rhs, "");
}
- fn airShl(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
+ fn airShl(self: *FuncGen, inst: Air.Inst.Index, sat: bool) !?*const llvm.Value {
if (self.liveness.isUnused(inst))
return null;
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
@@ -2186,6 +2212,12 @@ pub const FuncGen = struct {
self.builder.buildZExt(rhs, try self.dg.llvmType(lhs_type), "")
else
rhs;
+ if (sat) {
+ return if (lhs_type.isSignedInt())
+ self.builder.buildSShlSat(lhs, casted_rhs, "")
+ else
+ self.builder.buildUShlSat(lhs, casted_rhs, "");
+ }
return self.builder.buildShl(lhs, casted_rhs, "");
}
diff --git a/src/codegen/llvm/bindings.zig b/src/codegen/llvm/bindings.zig
index 9d32682260..178c381235 100644
--- a/src/codegen/llvm/bindings.zig
+++ b/src/codegen/llvm/bindings.zig
@@ -397,6 +397,12 @@ pub const Builder = opaque {
pub const buildNUWAdd = LLVMBuildNUWAdd;
extern fn LLVMBuildNUWAdd(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
+ pub const buildSAddSat = ZigLLVMBuildSAddSat;
+ extern fn ZigLLVMBuildSAddSat(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
+
+ pub const buildUAddSat = ZigLLVMBuildUAddSat;
+ extern fn ZigLLVMBuildUAddSat(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
+
pub const buildFSub = LLVMBuildFSub;
extern fn LLVMBuildFSub(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
@@ -409,6 +415,12 @@ pub const Builder = opaque {
pub const buildNUWSub = LLVMBuildNUWSub;
extern fn LLVMBuildNUWSub(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
+ pub const buildSSubSat = ZigLLVMBuildSSubSat;
+ extern fn ZigLLVMBuildSSubSat(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
+
+ pub const buildUSubSat = ZigLLVMBuildUSubSat;
+ extern fn ZigLLVMBuildUSubSat(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
+
pub const buildFMul = LLVMBuildFMul;
extern fn LLVMBuildFMul(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
@@ -421,6 +433,12 @@ pub const Builder = opaque {
pub const buildNUWMul = LLVMBuildNUWMul;
extern fn LLVMBuildNUWMul(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
+ pub const buildSMulFixSat = ZigLLVMBuildSMulFixSat;
+ extern fn ZigLLVMBuildSMulFixSat(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
+
+ pub const buildUMulFixSat = ZigLLVMBuildUMulFixSat;
+ extern fn ZigLLVMBuildUMulFixSat(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
+
pub const buildUDiv = LLVMBuildUDiv;
extern fn LLVMBuildUDiv(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
@@ -451,6 +469,12 @@ pub const Builder = opaque {
pub const buildShl = LLVMBuildShl;
extern fn LLVMBuildShl(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
+ pub const buildSShlSat = ZigLLVMBuildSShlSat;
+ extern fn ZigLLVMBuildSShlSat(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
+
+ pub const buildUShlSat = ZigLLVMBuildUShlSat;
+ extern fn ZigLLVMBuildUShlSat(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
+
pub const buildOr = LLVMBuildOr;
extern fn LLVMBuildOr(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;