aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDaniele Cocca <daniele.cocca@gmail.com>2022-03-13 21:37:36 +0000
committerAndrew Kelley <andrew@ziglang.org>2022-03-19 21:01:36 -0400
commitb6203b89d6b41f17e44f7806f2244309fa3bd86c (patch)
tree3528624c5803ba60c2797378ef4f2fb70cc4fe78 /src
parent1bd595ceea7a0d888d09cd54e3ee39a548beb0db (diff)
downloadzig-b6203b89d6b41f17e44f7806f2244309fa3bd86c.tar.gz
zig-b6203b89d6b41f17e44f7806f2244309fa3bd86c.zip
CBE: implement mod, divFloor, divTrunc
Diffstat (limited to 'src')
-rw-r--r--src/codegen/c.zig51
-rw-r--r--src/link/C/zig.h78
2 files changed, 126 insertions, 3 deletions
diff --git a/src/codegen/c.zig b/src/codegen/c.zig
index 88d26789cf..5c023c3dff 100644
--- a/src/codegen/c.zig
+++ b/src/codegen/c.zig
@@ -1663,10 +1663,20 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
.mul => try airBinOp (f, inst, " * "),
// TODO use a different strategy for div that communicates to the optimizer
// that wrapping is UB.
- .div_float, .div_exact, .div_trunc => try airBinOp( f, inst, " / "),
- .div_floor => try airBinOp( f, inst, " divfloor "),
+ .div_float, .div_exact => try airBinOp( f, inst, " / "),
+ .div_trunc => blk: {
+ const bin_op = f.air.instructions.items(.data)[inst].bin_op;
+ const lhs_ty = f.air.typeOf(bin_op.lhs);
+ // For binary operations @TypeOf(lhs)==@TypeOf(rhs),
+ // so we only check one.
+ break :blk if (lhs_ty.isInt())
+ try airBinOp(f, inst, " / ")
+ else
+ try airBinOpBuiltinCall(f, inst, "div_trunc");
+ },
+ .div_floor => try airBinOpBuiltinCall(f, inst, "div_floor"),
.rem => try airBinOp( f, inst, " % "),
- .mod => try airBinOp( f, inst, " mod "), // TODO implement modulus division
+ .mod => try airBinOpBuiltinCall(f, inst, "mod"),
.addwrap => try airWrapOp(f, inst, " + ", "addw_"),
.subwrap => try airWrapOp(f, inst, " - ", "subw_"),
@@ -3467,6 +3477,41 @@ fn airBuiltinCall(f: *Function, inst: Air.Inst.Index, fn_name: [*:0]const u8) !C
return local;
}
+fn airBinOpBuiltinCall(f: *Function, inst: Air.Inst.Index, fn_name: [*:0]const u8) !CValue {
+ if (f.liveness.isUnused(inst)) return CValue.none;
+
+ const inst_ty = f.air.typeOfIndex(inst);
+ const local = try f.allocLocal(inst_ty, .Const);
+ const bin_op = f.air.instructions.items(.data)[inst].bin_op;
+ const lhs_ty = f.air.typeOf(bin_op.lhs);
+ const target = f.object.dg.module.getTarget();
+ const writer = f.object.writer();
+
+ // For binary operations @TypeOf(lhs)==@TypeOf(rhs), so we only check one.
+ if (lhs_ty.isInt()) {
+ const int_info = lhs_ty.intInfo(target);
+ const c_bits = toCIntBits(int_info.bits) orelse
+ return f.fail("TODO: C backend: implement integer types larger than 128 bits", .{});
+ const prefix_byte: u8 = switch (int_info.signedness) {
+ .signed => 'i',
+ .unsigned => 'u',
+ };
+ try writer.print(" = zig_{s}_{c}{d}", .{ fn_name, prefix_byte, c_bits });
+ } else if (lhs_ty.isRuntimeFloat()) {
+ const c_bits = lhs_ty.floatBits(target);
+ try writer.print(" = zig_{s}_f{d}", .{ fn_name, c_bits });
+ } else {
+ return f.fail("TODO: C backend: implement airBinOpBuiltinCall for type {s}", .{@tagName(lhs_ty.tag())});
+ }
+
+ try writer.writeByte('(');
+ try f.writeCValue(writer, try f.resolveInst(bin_op.lhs));
+ try writer.writeAll(", ");
+ try f.writeCValue(writer, try f.resolveInst(bin_op.rhs));
+ try writer.writeAll(");\n");
+ return local;
+}
+
fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue {
const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
const extra = f.air.extraData(Air.Cmpxchg, ty_pl.payload).data;
diff --git a/src/link/C/zig.h b/src/link/C/zig.h
index 7259ba19ce..85c7856d2b 100644
--- a/src/link/C/zig.h
+++ b/src/link/C/zig.h
@@ -750,3 +750,81 @@ static inline uint128_t zig_bit_reverse_u128(uint128_t value, uint8_t zig_type_b
}
#define zig_bit_reverse_i128 zig_bit_reverse_u128
+
+static inline float zig_div_truncf(float numerator, float denominator) {
+ return __builtin_truncf(numerator / denominator);
+}
+
+static inline double zig_div_trunc(double numerator, double denominator) {
+ return __builtin_trunc(numerator / denominator);
+}
+
+static inline long double zig_div_truncl(long double numerator, long double denominator) {
+ return __builtin_truncf(numerator / denominator);
+}
+
+#define zig_div_trunc_f16 zig_div_truncf
+#define zig_div_trunc_f32 zig_div_truncf
+#define zig_div_trunc_f64 zig_div_trunc
+#define zig_div_trunc_f80 zig_div_truncl
+#define zig_div_trunc_f128 zig_div_truncl
+
+#define zig_div_floorf(numerator, denominator) \
+ __builtin_floorf((float)(numerator) / (float)(denominator))
+
+#define zig_div_floor(numerator, denominator) \
+ __builtin_floor((double)(numerator) / (double)(denominator))
+
+#define zig_div_floorl(numerator, denominator) \
+ __builtin_floorl((long double)(numerator) / (long double)(denominator))
+
+#define zig_div_floor_f16 zig_div_floorf
+#define zig_div_floor_f32 zig_div_floorf
+#define zig_div_floor_f64 zig_div_floor
+#define zig_div_floor_f80 zig_div_floorl
+#define zig_div_floor_f128 zig_div_floorl
+
+#define zig_div_floor_u8 zig_div_floorf
+#define zig_div_floor_i8 zig_div_floorf
+#define zig_div_floor_u16 zig_div_floorf
+#define zig_div_floor_i16 zig_div_floorf
+#define zig_div_floor_u32 zig_div_floor
+#define zig_div_floor_i32 zig_div_floor
+#define zig_div_floor_u64 zig_div_floor
+#define zig_div_floor_i64 zig_div_floor
+#define zig_div_floor_u128 zig_div_floorl
+#define zig_div_floor_i128 zig_div_floorl
+
+static inline float zig_modf(float numerator, float denominator) {
+ return (numerator - (zig_div_floorf(numerator, denominator) * denominator));
+}
+
+static inline double zig_mod(double numerator, double denominator) {
+ return (numerator - (zig_div_floor(numerator, denominator) * denominator));
+}
+
+static inline long double zig_modl(long double numerator, long double denominator) {
+ return (numerator - (zig_div_floorl(numerator, denominator) * denominator));
+}
+
+#define zig_mod_f16 zig_modf
+#define zig_mod_f32 zig_modf
+#define zig_mod_f64 zig_mod
+#define zig_mod_f80 zig_modl
+#define zig_mod_f128 zig_modl
+
+#define zig_mod_int(ZigType, CType) \
+ static inline CType zig_mod_##ZigType(CType numerator, CType denominator) { \
+ return (numerator - (zig_div_floor_##ZigType(numerator, denominator) * denominator)); \
+ }
+
+zig_mod_int( u8, uint8_t)
+zig_mod_int( i8, int8_t)
+zig_mod_int( u16, uint16_t)
+zig_mod_int( i16, int16_t)
+zig_mod_int( u32, uint32_t)
+zig_mod_int( i32, int32_t)
+zig_mod_int( u64, uint64_t)
+zig_mod_int( i64, int64_t)
+zig_mod_int(u128, uint128_t)
+zig_mod_int(i128, int128_t)