| ... | ... | @@ -3038,7 +3038,6 @@ fn analyzeInstElemPtr(self: *Module, scope: *Scope, inst: *zir.Inst.ElemPtr) Inn |
| 3038 | 3038 | } |
| 3039 | 3039 | |
| 3040 | 3040 | fn analyzeInstSub(self: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { |
| 3041 | | return self.fail(scope, inst.base.src, "TODO implement analysis of sub", .{}); |
| 3042 | 3041 | } |
| 3043 | 3042 | |
| 3044 | 3043 | fn 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 |
| 3048 | 3047 | const lhs = try self.resolveInst(scope, inst.positionals.lhs); |
| 3049 | 3048 | const rhs = try self.resolveInst(scope, inst.positionals.rhs); |
| 3050 | 3049 | |
| 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(); |
| 3057 | 3053 | |
| 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; |
| 3083 | 3055 | |
| 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); |
| 3089 | 3063 | } |
| 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 | } |
| 3090 | 3080 | |
| 3081 | /// Analyzes operands that are known at comptime |
| 3082 | fn 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 | }); |
| 3091 | 3090 | const b = try self.requireRuntimeBlock(scope, inst.base.src); |
| 3092 | 3091 | return self.addBinOp(b, inst.base.src, lhs.ty, .add, lhs, rhs); |
| 3093 | 3092 | } |
| 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 | }); |
| 3095 | 3126 | } |
| 3096 | 3127 | |
| 3097 | 3128 | fn analyzeInstDeref(self: *Module, scope: *Scope, deref: *zir.Inst.UnOp) InnerError!*Inst { |