aboutsummaryrefslogtreecommitdiff
path: root/src/codegen
diff options
context:
space:
mode:
authorTravis Staloch <twostepted@gmail.com>2021-09-08 15:19:03 -0700
committerAndrew Kelley <andrew@ziglang.org>2021-09-28 17:03:41 -0700
commitb9a95f2dd94e6175322d3388c3936eb600ec90ea (patch)
tree186a31fd920ca47bc15c3a426b9dfa8d67756ada /src/codegen
parent29f41896ed9d99e82a88f4b63efa182ca0d2f93c (diff)
downloadzig-b9a95f2dd94e6175322d3388c3936eb600ec90ea.tar.gz
zig-b9a95f2dd94e6175322d3388c3936eb600ec90ea.zip
sat-arithmetic: add c backend support
- modify AstGen binOpExt()/assignBinOpExt() to accept generic extended payload T - rework Sema zirSatArithmetic() to use existing sema.analyzeArithmetic() by adding an `opt_extended` parameter. - add airSatOp() to codegen/c.zig - add saturating functions to src/link/C/zig.h
Diffstat (limited to 'src/codegen')
-rw-r--r--src/codegen/c.zig120
-rw-r--r--src/codegen/llvm.zig6
2 files changed, 120 insertions, 6 deletions
diff --git a/src/codegen/c.zig b/src/codegen/c.zig
index dce0c10b4c..9ded6fe0e8 100644
--- a/src/codegen/c.zig
+++ b/src/codegen/c.zig
@@ -885,17 +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", .{}),
+ .addsat => return f.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", .{}),
+ .subsat => return f.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", .{}),
+ .mulsat => return f.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, " / "),
@@ -919,6 +919,8 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
.shr => try airBinOp(f, inst, " >> "),
.shl => try airBinOp(f, inst, " << "),
+ .shl_sat => return f.fail("TODO: C backend: implement codegen for mulsat", .{}),
+
.not => try airNot( f, inst),
@@ -1312,6 +1314,118 @@ fn airWrapOp(
return ret;
}
+fn airSatOp(
+ o: *Object,
+ inst: Air.Inst.Index,
+ str_op: [*:0]const u8,
+ fn_op: [*:0]const u8,
+) !CValue {
+ if (o.liveness.isUnused(inst))
+ return CValue.none;
+
+ const bin_op = o.air.instructions.items(.data)[inst].bin_op;
+ const inst_ty = o.air.typeOfIndex(inst);
+ const int_info = inst_ty.intInfo(o.dg.module.getTarget());
+ const bits = int_info.bits;
+
+ // if it's an unsigned int with non-arbitrary bit size then we can just add
+ const ok_bits = switch (bits) {
+ 8, 16, 32, 64, 128 => true,
+ else => false,
+ };
+
+ if (bits > 64) {
+ return f.fail("TODO: C backend: airSatOp for large integers", .{});
+ }
+
+ var min_buf: [80]u8 = undefined;
+ const min = switch (int_info.signedness) {
+ .unsigned => "0",
+ else => switch (inst_ty.tag()) {
+ .c_short => "SHRT_MIN",
+ .c_int => "INT_MIN",
+ .c_long => "LONG_MIN",
+ .c_longlong => "LLONG_MIN",
+ .isize => "INTPTR_MIN",
+ else => blk: {
+ const val = -1 * std.math.pow(i65, 2, @intCast(i65, bits - 1));
+ break :blk std.fmt.bufPrint(&min_buf, "{d}", .{val}) catch |err| switch (err) {
+ error.NoSpaceLeft => unreachable,
+ else => |e| return e,
+ };
+ },
+ },
+ };
+
+ var max_buf: [80]u8 = undefined;
+ const max = switch (inst_ty.tag()) {
+ .c_short => "SHRT_MAX",
+ .c_ushort => "USHRT_MAX",
+ .c_int => "INT_MAX",
+ .c_uint => "UINT_MAX",
+ .c_long => "LONG_MAX",
+ .c_ulong => "ULONG_MAX",
+ .c_longlong => "LLONG_MAX",
+ .c_ulonglong => "ULLONG_MAX",
+ .isize => "INTPTR_MAX",
+ .usize => "UINTPTR_MAX",
+ else => blk: {
+ const pow_bits = switch (int_info.signedness) {
+ .signed => bits - 1,
+ .unsigned => bits,
+ };
+ const val = std.math.pow(u65, 2, pow_bits) - 1;
+ break :blk std.fmt.bufPrint(&max_buf, "{}", .{val}) catch |err| switch (err) {
+ error.NoSpaceLeft => unreachable,
+ else => |e| return e,
+ };
+ },
+ };
+
+ const lhs = try o.resolveInst(bin_op.lhs);
+ const rhs = try o.resolveInst(bin_op.rhs);
+ const w = o.writer();
+
+ const ret = try o.allocLocal(inst_ty, .Mut);
+ try w.print(" = zig_{s}", .{fn_op});
+
+ switch (inst_ty.tag()) {
+ .isize => try w.writeAll("isize"),
+ .c_short => try w.writeAll("short"),
+ .c_int => try w.writeAll("int"),
+ .c_long => try w.writeAll("long"),
+ .c_longlong => try w.writeAll("longlong"),
+ else => {
+ const prefix_byte: u8 = switch (int_info.signedness) {
+ .signed => 'i',
+ .unsigned => 'u',
+ };
+ for ([_]u8{ 8, 16, 32, 64 }) |nbits| {
+ if (bits <= nbits) {
+ try w.print("{c}{d}", .{ prefix_byte, nbits });
+ break;
+ }
+ } else {
+ unreachable;
+ }
+ },
+ }
+
+ try w.writeByte('(');
+ try o.writeCValue(w, lhs);
+ try w.writeAll(", ");
+ try o.writeCValue(w, rhs);
+
+ if (int_info.signedness == .signed) {
+ try w.print(", {s}", .{min});
+ }
+
+ try w.print(", {s});", .{max});
+ try o.indent_writer.insertNewline();
+
+ return ret;
+}
+
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 c21985d1c5..733984a9d6 100644
--- a/src/codegen/llvm.zig
+++ b/src/codegen/llvm.zig
@@ -2038,7 +2038,7 @@ pub const FuncGen = struct {
const rhs = try self.resolveInst(bin_op.rhs);
const inst_ty = self.air.typeOfIndex(inst);
- if (inst_ty.isFloat()) return self.builder.buildFAdd(lhs, rhs, "");
+ if (inst_ty.isAnyFloat()) return self.builder.buildFAdd(lhs, rhs, "");
if (ty == .wrapping)
return self.builder.buildAdd(lhs, rhs, "")
else if (ty == .saturated) {
@@ -2060,7 +2060,7 @@ pub const FuncGen = struct {
const rhs = try self.resolveInst(bin_op.rhs);
const inst_ty = self.air.typeOfIndex(inst);
- if (inst_ty.isFloat()) return self.builder.buildFSub(lhs, rhs, "");
+ if (inst_ty.isAnyFloat()) return self.builder.buildFSub(lhs, rhs, "");
if (ty == .wrapping)
return self.builder.buildSub(lhs, rhs, "")
else if (ty == .saturated) {
@@ -2082,7 +2082,7 @@ pub const FuncGen = struct {
const rhs = try self.resolveInst(bin_op.rhs);
const inst_ty = self.air.typeOfIndex(inst);
- if (inst_ty.isFloat()) return self.builder.buildFMul(lhs, rhs, "");
+ if (inst_ty.isAnyFloat()) return self.builder.buildFMul(lhs, rhs, "");
if (ty == .wrapping)
return self.builder.buildMul(lhs, rhs, "")
else if (ty == .saturated) {