| ... | @@ -3038,7 +3038,6 @@ fn analyzeInstElemPtr(self: *Module, scope: *Scope, inst: *zir.Inst.ElemPtr) Inn | ... | @@ -3038,7 +3038,6 @@ fn analyzeInstElemPtr(self: *Module, scope: *Scope, inst: *zir.Inst.ElemPtr) Inn |
| 3038 | } | 3038 | } |
| 3039 | | 3039 | |
| 3040 | fn analyzeInstSub(self: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { | 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 | fn analyzeInstAdd(self: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { | 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,50 +3047,82 @@ fn analyzeInstAdd(self: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerErro |
| 3048 | const lhs = try self.resolveInst(scope, inst.positionals.lhs); | 3047 | const lhs = try self.resolveInst(scope, inst.positionals.lhs); |
| 3049 | const rhs = try self.resolveInst(scope, inst.positionals.rhs); | 3048 | const rhs = try self.resolveInst(scope, inst.positionals.rhs); |
| 3050 | | 3049 | |
| 3051 | if ((lhs.ty.zigTypeTag() == .Int or lhs.ty.zigTypeTag() == .ComptimeInt) and | 3050 | const instructions = &[_]*Inst{ lhs, rhs }; |
| 3052 | (rhs.ty.zigTypeTag() == .Int or rhs.ty.zigTypeTag() == .ComptimeInt)) | 3051 | const resolved_type = try self.resolvePeerTypes(scope, instructions); |
| 3053 | { | 3052 | const resolved_tag = resolved_type.zigTypeTag(); |
| 3054 | if (!lhs.ty.eql(rhs.ty)) { | | |
| 3055 | return self.fail(scope, inst.base.src, "TODO implement peer type resolution", .{}); | | |
| 3056 | } | | |
| 3057 | | 3053 | |
| 3058 | if (lhs.value()) |lhs_val| { | 3054 | const is_int = resolved_tag == .Int or resolved_tag == .ComptimeInt; |
| 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 | }; | | |
| 3083 | | 3055 | |
| 3084 | return self.constInst(scope, inst.base.src, .{ | 3056 | if (!is_int) { |
| 3085 | .ty = lhs.ty, | 3057 | return self.fail(scope, inst.base.src, "TODO analyze arithmetic for types {} and {}", .{ lhs.ty.zigTypeTag(), rhs.ty.zigTypeTag() }); |
| 3086 | .val = Value.initPayload(val_payload), | 3058 | } |
| 3087 | }); | 3059 | |
| 3088 | } | 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 | const b = try self.requireRuntimeBlock(scope, inst.base.src); | 3090 | const b = try self.requireRuntimeBlock(scope, inst.base.src); |
| 3092 | return self.addBinOp(b, inst.base.src, lhs.ty, .add, lhs, rhs); | 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 | fn analyzeInstDeref(self: *Module, scope: *Scope, deref: *zir.Inst.UnOp) InnerError!*Inst { | 3128 | fn analyzeInstDeref(self: *Module, scope: *Scope, deref: *zir.Inst.UnOp) InnerError!*Inst { |