diff options
| author | Travis Staloch <twostepted@gmail.com> | 2021-09-02 13:50:24 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2021-09-28 17:02:43 -0700 |
| commit | 29f41896ed9d99e82a88f4b63efa182ca0d2f93c (patch) | |
| tree | 1e6eb1159df89f79b04f050da662653925c77b1c /src/codegen | |
| parent | 79bc5891c1c4cde0592fe1b10b6c9a85914155cf (diff) | |
| download | zig-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.zig | 3 | ||||
| -rw-r--r-- | src/codegen/llvm.zig | 66 | ||||
| -rw-r--r-- | src/codegen/llvm/bindings.zig | 24 |
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; |
