Skip to content

Commit 1c640bf

Browse files
committed
CBE: implement mod, divFloor, divTrunc
1 parent c6cf40a commit 1c640bf

File tree

4 files changed

+160
-14
lines changed

4 files changed

+160
-14
lines changed

src/codegen/c.zig

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1663,10 +1663,11 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
16631663
.mul => try airBinOp (f, inst, " * "),
16641664
// TODO use a different strategy for div that communicates to the optimizer
16651665
// that wrapping is UB.
1666-
.div_float, .div_exact, .div_trunc => try airBinOp( f, inst, " / "),
1667-
.div_floor => try airBinOp( f, inst, " divfloor "),
1666+
.div_float, .div_exact => try airBinOp( f, inst, " / "),
1667+
.div_trunc => try airBinOpBuiltinCall(f, inst, "div_trunc"),
1668+
.div_floor => try airBinOpBuiltinCall(f, inst, "div_floor"),
16681669
.rem => try airBinOp( f, inst, " % "),
1669-
.mod => try airBinOp( f, inst, " mod "), // TODO implement modulus division
1670+
.mod => try airBinOpBuiltinCall(f, inst, "mod"),
16701671

16711672
.addwrap => try airWrapOp(f, inst, " + ", "addw_"),
16721673
.subwrap => try airWrapOp(f, inst, " - ", "subw_"),
@@ -3463,6 +3464,41 @@ fn airBuiltinCall(f: *Function, inst: Air.Inst.Index, fn_name: [*:0]const u8) !C
34633464
return local;
34643465
}
34653466

3467+
fn airBinOpBuiltinCall(f: *Function, inst: Air.Inst.Index, fn_name: [*:0]const u8) !CValue {
3468+
if (f.liveness.isUnused(inst)) return CValue.none;
3469+
3470+
const inst_ty = f.air.typeOfIndex(inst);
3471+
const local = try f.allocLocal(inst_ty, .Const);
3472+
const bin_op = f.air.instructions.items(.data)[inst].bin_op;
3473+
const lhs_ty = f.air.typeOf(bin_op.lhs);
3474+
const target = f.object.dg.module.getTarget();
3475+
const writer = f.object.writer();
3476+
3477+
// For binary operations @TypeOf(lhs)==@TypeOf(rhs), so we only check one.
3478+
if (lhs_ty.isInt()) {
3479+
const int_info = lhs_ty.intInfo(target);
3480+
const c_bits = toCIntBits(int_info.bits) orelse
3481+
return f.fail("TODO: C backend: implement integer types larger than 128 bits", .{});
3482+
const prefix_byte: u8 = switch (int_info.signedness) {
3483+
.signed => 'i',
3484+
.unsigned => 'u',
3485+
};
3486+
try writer.print(" = zig_{s}_{c}{d}", .{ fn_name, prefix_byte, c_bits });
3487+
} else if (lhs_ty.isRuntimeFloat()) {
3488+
const c_bits = lhs_ty.floatBits(target);
3489+
try writer.print(" = zig_{s}_f{d}", .{ fn_name, c_bits });
3490+
} else {
3491+
return f.fail("TODO: C backend: implement airBinOpBuiltinCall for type {s}", .{@tagName(lhs_ty.tag())});
3492+
}
3493+
3494+
try writer.writeByte('(');
3495+
try f.writeCValue(writer, try f.resolveInst(bin_op.lhs));
3496+
try writer.writeAll(", ");
3497+
try f.writeCValue(writer, try f.resolveInst(bin_op.rhs));
3498+
try writer.writeAll(");\n");
3499+
return local;
3500+
}
3501+
34663502
fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue {
34673503
const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
34683504
const extra = f.air.extraData(Air.Cmpxchg, ty_pl.payload).data;

src/link/C/zig.h

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -750,3 +750,97 @@ static inline uint128_t zig_bit_reverse_u128(uint128_t value, uint8_t zig_type_b
750750
}
751751

752752
#define zig_bit_reverse_i128 zig_bit_reverse_u128
753+
754+
static inline float zig_div_truncf(float numerator, float denominator) {
755+
return __builtin_truncf(numerator / denominator);
756+
}
757+
758+
static inline double zig_div_trunc(double numerator, double denominator) {
759+
return __builtin_trunc(numerator / denominator);
760+
}
761+
762+
static inline long double zig_div_truncl(long double numerator, long double denominator) {
763+
return __builtin_truncf(numerator / denominator);
764+
}
765+
766+
#define zig_div_trunc_f16 zig_div_truncf
767+
#define zig_div_trunc_f32 zig_div_truncf
768+
#define zig_div_trunc_f64 zig_div_trunc
769+
#define zig_div_trunc_f80 zig_div_truncl
770+
#define zig_div_trunc_f128 zig_div_truncl
771+
772+
#define zig_div_trunc_int(ZigType, CType) \
773+
static inline CType zig_div_trunc_##ZigType(CType numerator, CType denominator) { \
774+
return numerator / denominator; \
775+
}
776+
777+
zig_div_trunc_int( u8, uint8_t)
778+
zig_div_trunc_int( i8, int8_t)
779+
zig_div_trunc_int( u16, uint16_t)
780+
zig_div_trunc_int( i16, int16_t)
781+
zig_div_trunc_int( u32, uint32_t)
782+
zig_div_trunc_int( i32, int32_t)
783+
zig_div_trunc_int( u64, uint64_t)
784+
zig_div_trunc_int( i64, int64_t)
785+
zig_div_trunc_int(u128, uint128_t)
786+
zig_div_trunc_int(i128, int128_t)
787+
788+
#define zig_div_floorf(numerator, denominator) \
789+
__builtin_floorf((float)(numerator) / (float)(denominator))
790+
791+
#define zig_div_floor(numerator, denominator) \
792+
__builtin_floor((double)(numerator) / (double)(denominator))
793+
794+
#define zig_div_floorl(numerator, denominator) \
795+
__builtin_floorl((long double)(numerator) / (long double)(denominator))
796+
797+
#define zig_div_floor_f16 zig_div_floorf
798+
#define zig_div_floor_f32 zig_div_floorf
799+
#define zig_div_floor_f64 zig_div_floor
800+
#define zig_div_floor_f80 zig_div_floorl
801+
#define zig_div_floor_f128 zig_div_floorl
802+
803+
#define zig_div_floor_u8 zig_div_floorf
804+
#define zig_div_floor_i8 zig_div_floorf
805+
#define zig_div_floor_u16 zig_div_floorf
806+
#define zig_div_floor_i16 zig_div_floorf
807+
#define zig_div_floor_u32 zig_div_floor
808+
#define zig_div_floor_i32 zig_div_floor
809+
#define zig_div_floor_u64 zig_div_floor
810+
#define zig_div_floor_i64 zig_div_floor
811+
#define zig_div_floor_u128 zig_div_floorl
812+
#define zig_div_floor_i128 zig_div_floorl
813+
814+
static inline float zig_modf(float numerator, float denominator) {
815+
return (numerator - (zig_div_floorf(numerator, denominator) * denominator));
816+
}
817+
818+
static inline double zig_mod(double numerator, double denominator) {
819+
return (numerator - (zig_div_floor(numerator, denominator) * denominator));
820+
}
821+
822+
static inline long double zig_modl(long double numerator, long double denominator) {
823+
return (numerator - (zig_div_floorl(numerator, denominator) * denominator));
824+
}
825+
826+
#define zig_mod_f16 zig_modf
827+
#define zig_mod_f32 zig_modf
828+
#define zig_mod_f64 zig_mod
829+
#define zig_mod_f80 zig_modl
830+
#define zig_mod_f128 zig_modl
831+
832+
#define zig_mod_int(ZigType, CType) \
833+
static inline CType zig_mod_##ZigType(CType numerator, CType denominator) { \
834+
return (numerator - (zig_div_floor_##ZigType(numerator, denominator) * denominator)); \
835+
}
836+
837+
zig_mod_int( u8, uint8_t)
838+
zig_mod_int( i8, int8_t)
839+
zig_mod_int( u16, uint16_t)
840+
zig_mod_int( i16, int16_t)
841+
zig_mod_int( u32, uint32_t)
842+
zig_mod_int( i32, int32_t)
843+
zig_mod_int( u64, uint64_t)
844+
zig_mod_int( i64, int64_t)
845+
zig_mod_int(u128, uint128_t)
846+
zig_mod_int(i128, int128_t)

test/behavior/int_div.zig

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ const expect = std.testing.expect;
44

55
test "integer division" {
66
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
7-
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
87
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
98
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
109

test/behavior/math.zig

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,6 @@ fn testBinaryNot(x: u16) !void {
385385
}
386386

387387
test "division" {
388-
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
389388
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
390389
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
391390
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
@@ -394,22 +393,18 @@ test "division" {
394393
try testDivision();
395394
comptime try testDivision();
396395
}
396+
397397
fn testDivision() !void {
398398
try expect(div(u32, 13, 3) == 4);
399-
try expect(div(f16, 1.0, 2.0) == 0.5);
400399
try expect(div(f32, 1.0, 2.0) == 0.5);
401400

402401
try expect(divExact(u32, 55, 11) == 5);
403402
try expect(divExact(i32, -55, 11) == -5);
404-
try expect(divExact(f16, 55.0, 11.0) == 5.0);
405-
try expect(divExact(f16, -55.0, 11.0) == -5.0);
406403
try expect(divExact(f32, 55.0, 11.0) == 5.0);
407404
try expect(divExact(f32, -55.0, 11.0) == -5.0);
408405

409406
try expect(divFloor(i32, 5, 3) == 1);
410407
try expect(divFloor(i32, -5, 3) == -2);
411-
try expect(divFloor(f16, 5.0, 3.0) == 1.0);
412-
try expect(divFloor(f16, -5.0, 3.0) == -2.0);
413408
try expect(divFloor(f32, 5.0, 3.0) == 1.0);
414409
try expect(divFloor(f32, -5.0, 3.0) == -2.0);
415410
try expect(divFloor(i32, -0x80000000, -2) == 0x40000000);
@@ -424,10 +419,6 @@ fn testDivision() !void {
424419
try expect(divTrunc(i32, -5, 3) == -1);
425420
try expect(divTrunc(i32, 9, -10) == 0);
426421
try expect(divTrunc(i32, -9, 10) == 0);
427-
try expect(divTrunc(f16, 5.0, 3.0) == 1.0);
428-
try expect(divTrunc(f16, -5.0, 3.0) == -1.0);
429-
try expect(divTrunc(f16, 9.0, -10.0) == 0.0);
430-
try expect(divTrunc(f16, -9.0, 10.0) == 0.0);
431422
try expect(divTrunc(f32, 5.0, 3.0) == 1.0);
432423
try expect(divTrunc(f32, -5.0, 3.0) == -1.0);
433424
try expect(divTrunc(f32, 9.0, -10.0) == 0.0);
@@ -468,6 +459,32 @@ fn testDivision() !void {
468459
);
469460
}
470461
}
462+
463+
test "division half-precision floats" {
464+
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
465+
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
466+
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
467+
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
468+
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
469+
470+
try testDivisionFP16();
471+
comptime try testDivisionFP16();
472+
}
473+
474+
fn testDivisionFP16() !void {
475+
try expect(div(f16, 1.0, 2.0) == 0.5);
476+
477+
try expect(divExact(f16, 55.0, 11.0) == 5.0);
478+
try expect(divExact(f16, -55.0, 11.0) == -5.0);
479+
480+
try expect(divFloor(f16, 5.0, 3.0) == 1.0);
481+
try expect(divFloor(f16, -5.0, 3.0) == -2.0);
482+
try expect(divTrunc(f16, 5.0, 3.0) == 1.0);
483+
try expect(divTrunc(f16, -5.0, 3.0) == -1.0);
484+
try expect(divTrunc(f16, 9.0, -10.0) == 0.0);
485+
try expect(divTrunc(f16, -9.0, 10.0) == 0.0);
486+
}
487+
471488
fn div(comptime T: type, a: T, b: T) T {
472489
return a / b;
473490
}

0 commit comments

Comments
 (0)