| author | |
| committer | |
| log | e878a6633f2447666217a5f9247af7c34507dca0 |
| tree | 86c3c8bb4e817ef9c09ca353c6b7481f73e0bf61 |
| parent | 56845082bc6fb88a27c18cc3403216f93dc8ba42 |
8 files changed, 51 insertions(+), 3 deletions(-)
src/Air.zig+5| ... | @@ -69,6 +69,10 @@ pub const Inst = struct { | ... | @@ -69,6 +69,10 @@ pub const Inst = struct { |
| 69 | /// is the same as both operands. | 69 | /// is the same as both operands. |
| 70 | /// Uses the `bin_op` field. | 70 | /// Uses the `bin_op` field. |
| 71 | div, | 71 | 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, | ||
| 72 | /// Add an offset to a pointer, returning a new pointer. | 76 | /// Add an offset to a pointer, returning a new pointer. |
| 73 | /// The offset is in element type units, not bytes. | 77 | /// The offset is in element type units, not bytes. |
| 74 | /// Wrapping is undefined behavior. | 78 | /// Wrapping is undefined behavior. |
| ... | @@ -462,6 +466,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { | ... | @@ -462,6 +466,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { |
| 462 | .mul, | 466 | .mul, |
| 463 | .mulwrap, | 467 | .mulwrap, |
| 464 | .div, | 468 | .div, |
| 469 | .rem, | ||
| 465 | .bit_and, | 470 | .bit_and, |
| 466 | .bit_or, | 471 | .bit_or, |
| 467 | .xor, | 472 | .xor, |
src/Liveness.zig+1| ... | @@ -231,6 +231,7 @@ fn analyzeInst( | ... | @@ -231,6 +231,7 @@ fn analyzeInst( |
| 231 | .mul, | 231 | .mul, |
| 232 | .mulwrap, | 232 | .mulwrap, |
| 233 | .div, | 233 | .div, |
| 234 | .rem, | ||
| 234 | .ptr_add, | 235 | .ptr_add, |
| 235 | .ptr_sub, | 236 | .ptr_sub, |
| 236 | .bit_and, | 237 | .bit_and, |
src/Sema.zig+11-3| ... | @@ -5714,6 +5714,14 @@ fn analyzeArithmetic( | ... | @@ -5714,6 +5714,14 @@ fn analyzeArithmetic( |
| 5714 | try sema.requireRuntimeBlock(block, lhs_src); | 5714 | try sema.requireRuntimeBlock(block, lhs_src); |
| 5715 | } | 5715 | } |
| 5716 | 5716 | ||
| 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 | |||
| 5717 | const air_tag: Air.Inst.Tag = switch (zir_tag) { | 5725 | const air_tag: Air.Inst.Tag = switch (zir_tag) { |
| 5718 | .add => .add, | 5726 | .add => .add, |
| 5719 | .addwrap => .addwrap, | 5727 | .addwrap => .addwrap, |
| ... | @@ -5722,6 +5730,8 @@ fn analyzeArithmetic( | ... | @@ -5722,6 +5730,8 @@ fn analyzeArithmetic( |
| 5722 | .mul => .mul, | 5730 | .mul => .mul, |
| 5723 | .mulwrap => .mulwrap, | 5731 | .mulwrap => .mulwrap, |
| 5724 | .div => .div, | 5732 | .div => .div, |
| 5733 | .mod_rem => .rem, | ||
| 5734 | .rem => .rem, | ||
| 5725 | else => return sema.mod.fail(&block.base, src, "TODO implement arithmetic for operand '{s}'", .{@tagName(zir_tag)}), | 5735 | else => return sema.mod.fail(&block.base, src, "TODO implement arithmetic for operand '{s}'", .{@tagName(zir_tag)}), |
| 5726 | }; | 5736 | }; |
| 5727 | 5737 | ||
| ... | @@ -7184,9 +7194,7 @@ fn zirMod(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!A | ... | @@ -7184,9 +7194,7 @@ fn zirMod(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!A |
| 7184 | } | 7194 | } |
| 7185 | 7195 | ||
| 7186 | fn zirRem(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 7196 | fn 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; | 7197 | return sema.zirArithmetic(block, inst); |
| 7188 | const src = inst_data.src(); | ||
| 7189 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirRem", .{}); | ||
| 7190 | } | 7198 | } |
| 7191 | 7199 | ||
| 7192 | fn zirShlExact(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 7200 | fn 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 { | ... | @@ -809,6 +809,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 809 | .mul => try self.airMul(inst), | 809 | .mul => try self.airMul(inst), |
| 810 | .mulwrap => try self.airMulWrap(inst), | 810 | .mulwrap => try self.airMulWrap(inst), |
| 811 | .div => try self.airDiv(inst), | 811 | .div => try self.airDiv(inst), |
| 812 | .rem => try self.airRem(inst), | ||
| 812 | 813 | ||
| 813 | .cmp_lt => try self.airCmp(inst, .lt), | 814 | .cmp_lt => try self.airCmp(inst, .lt), |
| 814 | .cmp_lte => try self.airCmp(inst, .lte), | 815 | .cmp_lte => try self.airCmp(inst, .lte), |
| ... | @@ -1266,6 +1267,14 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -1266,6 +1267,14 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1266 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 1267 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1267 | } | 1268 | } |
| 1268 | 1269 | ||
| 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 | |||
| 1269 | fn airBitAnd(self: *Self, inst: Air.Inst.Index) !void { | 1278 | fn airBitAnd(self: *Self, inst: Air.Inst.Index) !void { |
| 1270 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1279 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1271 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) { | 1280 | 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 | ... | @@ -858,6 +858,7 @@ fn genBody(o: *Object, body: []const Air.Inst.Index) error{ AnalysisFail, OutOfM |
| 858 | // TODO use a different strategy for div that communicates to the optimizer | 858 | // TODO use a different strategy for div that communicates to the optimizer |
| 859 | // that wrapping is UB. | 859 | // that wrapping is UB. |
| 860 | .div => try airBinOp( o, inst, " / "), | 860 | .div => try airBinOp( o, inst, " / "), |
| 861 | .rem => try airBinOp( o, inst, " % "), | ||
| 861 | 862 | ||
| 862 | .cmp_eq => try airBinOp(o, inst, " == "), | 863 | .cmp_eq => try airBinOp(o, inst, " == "), |
| 863 | .cmp_gt => try airBinOp(o, inst, " > "), | 864 | .cmp_gt => try airBinOp(o, inst, " > "), |
src/codegen/llvm.zig+14| ... | @@ -985,6 +985,7 @@ pub const FuncGen = struct { | ... | @@ -985,6 +985,7 @@ pub const FuncGen = struct { |
| 985 | .mul => try self.airMul(inst, false), | 985 | .mul => try self.airMul(inst, false), |
| 986 | .mulwrap => try self.airMul(inst, true), | 986 | .mulwrap => try self.airMul(inst, true), |
| 987 | .div => try self.airDiv(inst), | 987 | .div => try self.airDiv(inst), |
| 988 | .rem => try self.airRem(inst), | ||
| 988 | .ptr_add => try self.airPtrAdd(inst), | 989 | .ptr_add => try self.airPtrAdd(inst), |
| 989 | .ptr_sub => try self.airPtrSub(inst), | 990 | .ptr_sub => try self.airPtrSub(inst), |
| 990 | 991 | ||
| ... | @@ -1727,6 +1728,19 @@ pub const FuncGen = struct { | ... | @@ -1727,6 +1728,19 @@ pub const FuncGen = struct { |
| 1727 | return self.builder.buildUDiv(lhs, rhs, ""); | 1728 | return self.builder.buildUDiv(lhs, rhs, ""); |
| 1728 | } | 1729 | } |
| 1729 | 1730 | ||
| 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 | |||
| 1730 | fn airPtrAdd(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { | 1744 | fn airPtrAdd(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { |
| 1731 | if (self.liveness.isUnused(inst)) | 1745 | if (self.liveness.isUnused(inst)) |
| 1732 | return null; | 1746 | return null; |
src/codegen/llvm/bindings.zig+9| ... | @@ -386,6 +386,15 @@ pub const Builder = opaque { | ... | @@ -386,6 +386,15 @@ pub const Builder = opaque { |
| 386 | pub const buildFDiv = LLVMBuildFDiv; | 386 | pub const buildFDiv = LLVMBuildFDiv; |
| 387 | extern fn LLVMBuildFDiv(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value; | 387 | extern fn LLVMBuildFDiv(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value; |
| 388 | 388 | ||
| 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 | |||
| 389 | pub const buildAnd = LLVMBuildAnd; | 398 | pub const buildAnd = LLVMBuildAnd; |
| 390 | extern fn LLVMBuildAnd(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value; | 399 | extern fn LLVMBuildAnd(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value; |
| 391 | 400 |
src/print_air.zig+1| ... | @@ -109,6 +109,7 @@ const Writer = struct { | ... | @@ -109,6 +109,7 @@ const Writer = struct { |
| 109 | .mul, | 109 | .mul, |
| 110 | .mulwrap, | 110 | .mulwrap, |
| 111 | .div, | 111 | .div, |
| 112 | .rem, | ||
| 112 | .ptr_add, | 113 | .ptr_add, |
| 113 | .ptr_sub, | 114 | .ptr_sub, |
| 114 | .bit_and, | 115 | .bit_and, |