authorgravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2021-08-30 00:31:40-07:00
committergravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2021-08-30 00:31:40-07:00
loge878a6633f2447666217a5f9247af7c34507dca0
tree86c3c8bb4e817ef9c09ca353c6b7481f73e0bf61
parent56845082bc6fb88a27c18cc3403216f93dc8ba42

stage2: implement runtime `%` and `@rem`


8 files changed, 51 insertions(+), 3 deletions(-)

src/Air.zig+5
......@@ -69,6 +69,10 @@ pub const Inst = struct {
6969 /// is the same as both operands.
7070 /// Uses the `bin_op` field.
7171 div,
72 /// Integer or float remainder.
73 /// Both operands are guaranteed to be the same type, and the result type is the same as both operands.
74 /// Uses the `bin_op` field.
75 rem,
7276 /// Add an offset to a pointer, returning a new pointer.
7377 /// The offset is in element type units, not bytes.
7478 /// Wrapping is undefined behavior.
......@@ -462,6 +466,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
462466 .mul,
463467 .mulwrap,
464468 .div,
469 .rem,
465470 .bit_and,
466471 .bit_or,
467472 .xor,
src/Liveness.zig+1
......@@ -231,6 +231,7 @@ fn analyzeInst(
231231 .mul,
232232 .mulwrap,
233233 .div,
234 .rem,
234235 .ptr_add,
235236 .ptr_sub,
236237 .bit_and,
src/Sema.zig+11-3
......@@ -5714,6 +5714,14 @@ fn analyzeArithmetic(
57145714 try sema.requireRuntimeBlock(block, lhs_src);
57155715 }
57165716
5717 if (zir_tag == .mod_rem) {
5718 const dirty_lhs = lhs_ty.isSignedInt() or lhs_ty.isFloat();
5719 const dirty_rhs = rhs_ty.isSignedInt() or rhs_ty.isFloat();
5720 if (dirty_lhs or dirty_rhs) {
5721 return sema.mod.fail(&block.base, src, "remainder division with '{}' and '{}': signed integers and floats must use @rem or @mod", .{ lhs_ty, rhs_ty });
5722 }
5723 }
5724
57175725 const air_tag: Air.Inst.Tag = switch (zir_tag) {
57185726 .add => .add,
57195727 .addwrap => .addwrap,
......@@ -5722,6 +5730,8 @@ fn analyzeArithmetic(
57225730 .mul => .mul,
57235731 .mulwrap => .mulwrap,
57245732 .div => .div,
5733 .mod_rem => .rem,
5734 .rem => .rem,
57255735 else => return sema.mod.fail(&block.base, src, "TODO implement arithmetic for operand '{s}'", .{@tagName(zir_tag)}),
57265736 };
57275737
......@@ -7184,9 +7194,7 @@ fn zirMod(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!A
71847194}
71857195
71867196fn zirRem(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
7187 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
7188 const src = inst_data.src();
7189 return sema.mod.fail(&block.base, src, "TODO: Sema.zirRem", .{});
7197 return sema.zirArithmetic(block, inst);
71907198}
71917199
71927200fn zirShlExact(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
src/codegen.zig+9
......@@ -809,6 +809,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
809809 .mul => try self.airMul(inst),
810810 .mulwrap => try self.airMulWrap(inst),
811811 .div => try self.airDiv(inst),
812 .rem => try self.airRem(inst),
812813
813814 .cmp_lt => try self.airCmp(inst, .lt),
814815 .cmp_lte => try self.airCmp(inst, .lte),
......@@ -1266,6 +1267,14 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
12661267 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
12671268 }
12681269
1270 fn airRem(self: *Self, inst: Air.Inst.Index) !void {
1271 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1272 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) {
1273 else => return self.fail("TODO implement rem for {}", .{self.target.cpu.arch}),
1274 };
1275 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1276 }
1277
12691278 fn airBitAnd(self: *Self, inst: Air.Inst.Index) !void {
12701279 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
12711280 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) {
src/codegen/c.zig+1
......@@ -858,6 +858,7 @@ fn genBody(o: *Object, body: []const Air.Inst.Index) error{ AnalysisFail, OutOfM
858858 // TODO use a different strategy for div that communicates to the optimizer
859859 // that wrapping is UB.
860860 .div => try airBinOp( o, inst, " / "),
861 .rem => try airBinOp( o, inst, " % "),
861862
862863 .cmp_eq => try airBinOp(o, inst, " == "),
863864 .cmp_gt => try airBinOp(o, inst, " > "),
src/codegen/llvm.zig+14
......@@ -985,6 +985,7 @@ pub const FuncGen = struct {
985985 .mul => try self.airMul(inst, false),
986986 .mulwrap => try self.airMul(inst, true),
987987 .div => try self.airDiv(inst),
988 .rem => try self.airRem(inst),
988989 .ptr_add => try self.airPtrAdd(inst),
989990 .ptr_sub => try self.airPtrSub(inst),
990991
......@@ -1727,6 +1728,19 @@ pub const FuncGen = struct {
17271728 return self.builder.buildUDiv(lhs, rhs, "");
17281729 }
17291730
1731 fn airRem(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
1732 if (self.liveness.isUnused(inst)) return null;
1733
1734 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1735 const lhs = try self.resolveInst(bin_op.lhs);
1736 const rhs = try self.resolveInst(bin_op.rhs);
1737 const inst_ty = self.air.typeOfIndex(inst);
1738
1739 if (inst_ty.isFloat()) return self.builder.buildFRem(lhs, rhs, "");
1740 if (inst_ty.isSignedInt()) return self.builder.buildSRem(lhs, rhs, "");
1741 return self.builder.buildURem(lhs, rhs, "");
1742 }
1743
17301744 fn airPtrAdd(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
17311745 if (self.liveness.isUnused(inst))
17321746 return null;
src/codegen/llvm/bindings.zig+9
......@@ -386,6 +386,15 @@ pub const Builder = opaque {
386386 pub const buildFDiv = LLVMBuildFDiv;
387387 extern fn LLVMBuildFDiv(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
388388
389 pub const buildURem = LLVMBuildURem;
390 extern fn LLVMBuildURem(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
391
392 pub const buildSRem = LLVMBuildSRem;
393 extern fn LLVMBuildSRem(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
394
395 pub const buildFRem = LLVMBuildFRem;
396 extern fn LLVMBuildFRem(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
397
389398 pub const buildAnd = LLVMBuildAnd;
390399 extern fn LLVMBuildAnd(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
391400
src/print_air.zig+1
......@@ -109,6 +109,7 @@ const Writer = struct {
109109 .mul,
110110 .mulwrap,
111111 .div,
112 .rem,
112113 .ptr_add,
113114 .ptr_sub,
114115 .bit_and,