authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2020-07-17 23:04:44+02:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2020-07-24 17:16:48+02:00
logee7fbb9548fe0e049117f49d10fc0932d175d72d
tree4df7ca9a8273dace74c8a8f10d5cbf77a8d6ec48
parent198c09197bf5140e5fb324e1a78a4b5b66d982e5
signaturelock-open Commit is signed but in an unrecognized format.

Restructured arithmetic operations


2 files changed, 69 insertions(+), 39 deletions(-)

src-self-hosted/Module.zig+69-38
......@@ -3038,7 +3038,6 @@ fn analyzeInstElemPtr(self: *Module, scope: *Scope, inst: *zir.Inst.ElemPtr) Inn
30383038}
30393039
30403040fn analyzeInstSub(self: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {
3041 return self.fail(scope, inst.base.src, "TODO implement analysis of sub", .{});
30423041}
30433042
30443043fn analyzeInstAdd(self: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {
......@@ -3048,50 +3047,82 @@ fn analyzeInstAdd(self: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerErro
30483047 const lhs = try self.resolveInst(scope, inst.positionals.lhs);
30493048 const rhs = try self.resolveInst(scope, inst.positionals.rhs);
30503049
3051 if ((lhs.ty.zigTypeTag() == .Int or lhs.ty.zigTypeTag() == .ComptimeInt) and
3052 (rhs.ty.zigTypeTag() == .Int or rhs.ty.zigTypeTag() == .ComptimeInt))
3053 {
3054 if (!lhs.ty.eql(rhs.ty)) {
3055 return self.fail(scope, inst.base.src, "TODO implement peer type resolution", .{});
3056 }
3050 const instructions = &[_]*Inst{ lhs, rhs };
3051 const resolved_type = try self.resolvePeerTypes(scope, instructions);
3052 const resolved_tag = resolved_type.zigTypeTag();
30573053
3058 if (lhs.value()) |lhs_val| {
3059 if (rhs.value()) |rhs_val| {
3060 // TODO is this a performance issue? maybe we should try the operation without
3061 // resorting to BigInt first.
3062 var lhs_space: Value.BigIntSpace = undefined;
3063 var rhs_space: Value.BigIntSpace = undefined;
3064 const lhs_bigint = lhs_val.toBigInt(&lhs_space);
3065 const rhs_bigint = rhs_val.toBigInt(&rhs_space);
3066 const limbs = try scope.arena().alloc(
3067 std.math.big.Limb,
3068 std.math.max(lhs_bigint.limbs.len, rhs_bigint.limbs.len) + 1,
3069 );
3070 var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };
3071 result_bigint.add(lhs_bigint, rhs_bigint);
3072 const result_limbs = result_bigint.limbs[0..result_bigint.len];
3073
3074 const val_payload = if (result_bigint.positive) blk: {
3075 const val_payload = try scope.arena().create(Value.Payload.IntBigPositive);
3076 val_payload.* = .{ .limbs = result_limbs };
3077 break :blk &val_payload.base;
3078 } else blk: {
3079 const val_payload = try scope.arena().create(Value.Payload.IntBigNegative);
3080 val_payload.* = .{ .limbs = result_limbs };
3081 break :blk &val_payload.base;
3082 };
3054 const is_int = resolved_tag == .Int or resolved_tag == .ComptimeInt;
30833055
3084 return self.constInst(scope, inst.base.src, .{
3085 .ty = lhs.ty,
3086 .val = Value.initPayload(val_payload),
3087 });
3088 }
3056 if (!is_int) {
3057 return self.fail(scope, inst.base.src, "TODO analyze arithmetic for types {} and {}", .{ lhs.ty.zigTypeTag(), rhs.ty.zigTypeTag() });
3058 }
3059
3060 if (lhs.value()) |lhs_val| {
3061 if (rhs.value()) |rhs_val| {
3062 return self.analyzeInstMath(scope, resolved_type, &inst.base, lhs_val, rhs_val);
30893063 }
3064 }
3065
3066 const b = try self.requireRuntimeBlock(scope, inst.base.src);
3067
3068 return switch (inst.base.tag) {
3069 .add => self.addNewInstArgs(b, inst.base.src, resolved_type, Inst.Add, .{
3070 .lhs = lhs,
3071 .rhs = rhs,
3072 }),
3073 .sub => self.addNewInstArgs(b, inst.base.src, resolved_type, Inst.Sub, .{
3074 .lhs = lhs,
3075 .rhs = rhs,
3076 }),
3077 else => self.fail(scope, inst.base.src, "TODO Implement arithmetic for operand {}", .{@tagName(inst.base.tag)}),
3078 };
3079}
30903080
3081/// Analyzes operands that are known at comptime
3082fn analyzeInstMath(self: *Module, scope: *Scope, res_type: Type, base: *zir.Inst, lhs_val: Value, rhs_val: Value) InnerError!*Inst {
3083 // incase rhs is 0, simply return lhs without doing any calculations
3084 // TODO Once division is implemented we should throw an error when dividing by 0.
3085 if (rhs_val.tag() == .zero or rhs_val.tag() == .the_one_possible_value) {
3086 return self.constInst(scope, base.src, .{
3087 .ty = res_type,
3088 .val = lhs_val,
3089 });
30913090 const b = try self.requireRuntimeBlock(scope, inst.base.src);
30923091 return self.addBinOp(b, inst.base.src, lhs.ty, .add, lhs, rhs);
30933092 }
3094 return self.fail(scope, inst.base.src, "TODO analyze add for {} + {}", .{ lhs.ty.zigTypeTag(), rhs.ty.zigTypeTag() });
3093
3094 // TODO is this a performance issue? maybe we should try the operation without
3095 // resorting to BigInt first.
3096 var lhs_space: Value.BigIntSpace = undefined;
3097 var rhs_space: Value.BigIntSpace = undefined;
3098 const lhs_bigint = lhs_val.toBigInt(&lhs_space);
3099 const rhs_bigint = rhs_val.toBigInt(&rhs_space);
3100 const limbs = try scope.arena().alloc(
3101 std.math.big.Limb,
3102 std.math.max(lhs_bigint.limbs.len, rhs_bigint.limbs.len) + 1,
3103 );
3104 var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };
3105 switch (base.tag) {
3106 .add => result_bigint.add(lhs_bigint, rhs_bigint),
3107 .sub => result_bigint.sub(lhs_bigint, rhs_bigint),
3108 else => return error.AnalysisFail,
3109 }
3110 const result_limbs = result_bigint.limbs[0..result_bigint.len];
3111
3112 const val_payload = if (result_bigint.positive) blk: {
3113 const val_payload = try scope.arena().create(Value.Payload.IntBigPositive);
3114 val_payload.* = .{ .limbs = result_limbs };
3115 break :blk &val_payload.base;
3116 } else blk: {
3117 const val_payload = try scope.arena().create(Value.Payload.IntBigNegative);
3118 val_payload.* = .{ .limbs = result_limbs };
3119 break :blk &val_payload.base;
3120 };
3121
3122 return self.constInst(scope, base.src, .{
3123 .ty = res_type,
3124 .val = Value.initPayload(val_payload),
3125 });
30953126}
30963127
30973128fn analyzeInstDeref(self: *Module, scope: *Scope, deref: *zir.Inst.UnOp) InnerError!*Inst {
test/stage2/compare_output.zig-1
......@@ -172,7 +172,6 @@ pub fn addCases(ctx: *TestContext) !void {
172172 }
173173
174174 {
175 // TODO add a test case for comptime substraction of numbers
176175 var case = ctx.exe("substracting numbers at runtime", linux_x64);
177176 case.addCompareOutput(
178177 \\export fn _start() noreturn {