authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2020-07-22 22:13:11+02:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2020-07-24 17:16:48+02:00
log97e92d868e0a4636b95e3a499c7de9f1b84b0ec6
tree0a409a45450206196df3749e5382f3e09accf5fd
parentee7fbb9548fe0e049117f49d10fc0932d175d72d
signaturelock-open Commit is signed but in an unrecognized format.

Rebase and skeleton for float support


1 files changed, 99 insertions(+), 57 deletions(-)

src-self-hosted/Module.zig+99-57
...@@ -2400,8 +2400,7 @@ fn analyzeInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*In...@@ -2400,8 +2400,7 @@ fn analyzeInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*In
2400 .bitcast => return self.analyzeInstBitCast(scope, old_inst.castTag(.bitcast).?),2400 .bitcast => return self.analyzeInstBitCast(scope, old_inst.castTag(.bitcast).?),
2401 .floatcast => return self.analyzeInstFloatCast(scope, old_inst.castTag(.floatcast).?),2401 .floatcast => return self.analyzeInstFloatCast(scope, old_inst.castTag(.floatcast).?),
2402 .elemptr => return self.analyzeInstElemPtr(scope, old_inst.castTag(.elemptr).?),2402 .elemptr => return self.analyzeInstElemPtr(scope, old_inst.castTag(.elemptr).?),
2403 .add => return self.analyzeInstAdd(scope, old_inst.castTag(.add).?),2403 .add, .sub => return self.analyzeInstArithmetic(scope, old_inst.cast(zir.Inst.BinOp).?),
2404 .sub => return self.analyzeInstSub(scope, old_inst.castTag(.sub).?),
2405 .cmp_lt => return self.analyzeInstCmp(scope, old_inst.castTag(.cmp_lt).?, .lt),2404 .cmp_lt => return self.analyzeInstCmp(scope, old_inst.castTag(.cmp_lt).?, .lt),
2406 .cmp_lte => return self.analyzeInstCmp(scope, old_inst.castTag(.cmp_lte).?, .lte),2405 .cmp_lte => return self.analyzeInstCmp(scope, old_inst.castTag(.cmp_lte).?, .lte),
2407 .cmp_eq => return self.analyzeInstCmp(scope, old_inst.castTag(.cmp_eq).?, .eq),2406 .cmp_eq => return self.analyzeInstCmp(scope, old_inst.castTag(.cmp_eq).?, .eq),
...@@ -3037,10 +3036,15 @@ fn analyzeInstElemPtr(self: *Module, scope: *Scope, inst: *zir.Inst.ElemPtr) Inn...@@ -3037,10 +3036,15 @@ fn analyzeInstElemPtr(self: *Module, scope: *Scope, inst: *zir.Inst.ElemPtr) Inn
3037 return self.fail(scope, inst.base.src, "TODO implement more analyze elemptr", .{});3036 return self.fail(scope, inst.base.src, "TODO implement more analyze elemptr", .{});
3038}3037}
30393038
3040fn analyzeInstSub(self: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {3039fn floatOpAllowed(tag: zir.Inst.Tag) bool {
3040 // extend this swich as additional operators are implemented
3041 return switch (tag) {
3042 .add, .sub => true,
3043 else => false,
3044 };
3041}3045}
30423046
3043fn analyzeInstAdd(self: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {3047fn analyzeInstArithmetic(self: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {
3044 const tracy = trace(@src());3048 const tracy = trace(@src());
3045 defer tracy.end();3049 defer tracy.end();
30463050
...@@ -3049,80 +3053,118 @@ fn analyzeInstAdd(self: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerErro...@@ -3049,80 +3053,118 @@ fn analyzeInstAdd(self: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerErro
30493053
3050 const instructions = &[_]*Inst{ lhs, rhs };3054 const instructions = &[_]*Inst{ lhs, rhs };
3051 const resolved_type = try self.resolvePeerTypes(scope, instructions);3055 const resolved_type = try self.resolvePeerTypes(scope, instructions);
3052 const resolved_tag = resolved_type.zigTypeTag();
30533056
3054 const is_int = resolved_tag == .Int or resolved_tag == .ComptimeInt;3057 const scalar_type = if (resolved_type.zigTypeTag() == .Vector)
3058 resolved_type.elemType()
3059 else
3060 resolved_type;
3061
3062 const scalar_tag = scalar_type.zigTypeTag();
3063
3064 if (lhs.ty.zigTypeTag() == .Vector and rhs.ty.zigTypeTag() == .Vector) {
3065 if (lhs.ty.arrayLen() != rhs.ty.arrayLen()) {
3066 return self.fail(scope, inst.base.src, "vector length mismatch: {} and {}", .{
3067 lhs.ty.arrayLen(),
3068 rhs.ty.arrayLen(),
3069 });
3070 }
3071 return self.fail(scope, inst.base.src, "TODO implement support for vectors in analyzeInstBinOp", .{});
3072 } else if (lhs.ty.zigTypeTag() == .Vector or rhs.ty.zigTypeTag() == .Vector) {
3073 return self.fail(scope, inst.base.src, "mixed scalar and vector operands to comparison operator: '{}' and '{}'", .{
3074 lhs.ty,
3075 rhs.ty,
3076 });
3077 }
3078
3079 const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt;
3080 const is_float = scalar_tag == .Float or scalar_tag == .ComptimeFloat;
30553081
3056 if (!is_int) {3082 if (!is_int and !(is_float and floatOpAllowed(inst.base.tag))) {
3057 return self.fail(scope, inst.base.src, "TODO analyze arithmetic for types {} and {}", .{ lhs.ty.zigTypeTag(), rhs.ty.zigTypeTag() });3083 return self.fail(scope, inst.base.src, "invalid operands to binary expression: '{}' and '{}'", .{ @tagName(lhs.ty.zigTypeTag()), @tagName(rhs.ty.zigTypeTag()) });
3058 }3084 }
30593085
3060 if (lhs.value()) |lhs_val| {3086 if (lhs.value()) |lhs_val| {
3061 if (rhs.value()) |rhs_val| {3087 if (rhs.value()) |rhs_val| {
3062 return self.analyzeInstMath(scope, resolved_type, &inst.base, lhs_val, rhs_val);3088 return self.analyzeInstScalar(scope, scalar_type, inst, lhs_val, rhs_val);
3063 }3089 }
3064 }3090 }
30653091
3066 const b = try self.requireRuntimeBlock(scope, inst.base.src);3092 const b = try self.requireRuntimeBlock(scope, inst.base.src);
30673093 const ir_tag = switch (inst.base.tag) {
3068 return switch (inst.base.tag) {3094 .add => Inst.Tag.add,
3069 .add => self.addNewInstArgs(b, inst.base.src, resolved_type, Inst.Add, .{3095 .sub => Inst.Tag.sub,
3070 .lhs = lhs,3096 else => return self.fail(scope, inst.base.src, "TODO implement arithmetic for operand '{}''", .{@tagName(inst.base.tag)}),
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 };3097 };
3098
3099 if (is_float) {
3100 // Implicit cast the smaller one to the larger one.
3101 const dest_type = x: {
3102 if (lhs.ty.zigTypeTag() == .ComptimeFloat) {
3103 break :x rhs.ty;
3104 } else if (rhs.ty.zigTypeTag() == .ComptimeFloat) {
3105 break :x lhs.ty;
3106 }
3107 if (lhs.ty.floatBits(self.target()) >= rhs.ty.floatBits(self.target())) {
3108 break :x lhs.ty;
3109 } else {
3110 break :x rhs.ty;
3111 }
3112 };
3113 const casted_lhs = try self.coerce(scope, dest_type, lhs);
3114 const casted_rhs = try self.coerce(scope, dest_type, rhs);
3115 return self.addBinOp(b, inst.base.src, dest_type, ir_tag, casted_lhs, casted_rhs);
3116 }
3117
3118 return self.addBinOp(b, inst.base.src, resolved_type, ir_tag, lhs, rhs);
3079}3119}
30803120
3081/// Analyzes operands that are known at comptime3121/// 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 {3122fn analyzeInstScalar(self: *Module, scope: *Scope, res_type: Type, inst: *zir.Inst.BinOp, lhs_val: Value, rhs_val: Value) InnerError!*Inst {
3083 // incase rhs is 0, simply return lhs without doing any calculations3123 // 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.3124 // 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) {3125 if (rhs_val.tag() == .zero or rhs_val.tag() == .the_one_possible_value) {
3086 return self.constInst(scope, base.src, .{3126 return self.constInst(scope, inst.base.src, .{
3087 .ty = res_type,3127 .ty = res_type,
3088 .val = lhs_val,3128 .val = lhs_val,
3089 });3129 });
3090 const b = try self.requireRuntimeBlock(scope, inst.base.src);3130 }
3091 return self.addBinOp(b, inst.base.src, lhs.ty, .add, lhs, rhs);
3092 }
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 };
31213131
3122 return self.constInst(scope, base.src, .{3132 if (lhs_val.isFloat() or res_type.tag() == .comptime_float) {
3123 .ty = res_type,3133 return self.fail(scope, inst.base.src, "TODO implement arithmetic for floats", .{});
3124 .val = Value.initPayload(val_payload),3134 } else {
3125 });3135 // TODO is this a performance issue? maybe we should try the operation without
3136 // resorting to BigInt first.
3137 var lhs_space: Value.BigIntSpace = undefined;
3138 var rhs_space: Value.BigIntSpace = undefined;
3139 const lhs_bigint = lhs_val.toBigInt(&lhs_space);
3140 const rhs_bigint = rhs_val.toBigInt(&rhs_space);
3141 const limbs = try scope.arena().alloc(
3142 std.math.big.Limb,
3143 std.math.max(lhs_bigint.limbs.len, rhs_bigint.limbs.len) + 1,
3144 );
3145 var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };
3146 switch (inst.base.tag) {
3147 .add => result_bigint.add(lhs_bigint, rhs_bigint),
3148 .sub => result_bigint.sub(lhs_bigint, rhs_bigint),
3149 else => return error.AnalysisFail,
3150 }
3151 const result_limbs = result_bigint.limbs[0..result_bigint.len];
3152
3153 const val_payload = if (result_bigint.positive) blk: {
3154 const val_payload = try scope.arena().create(Value.Payload.IntBigPositive);
3155 val_payload.* = .{ .limbs = result_limbs };
3156 break :blk &val_payload.base;
3157 } else blk: {
3158 const val_payload = try scope.arena().create(Value.Payload.IntBigNegative);
3159 val_payload.* = .{ .limbs = result_limbs };
3160 break :blk &val_payload.base;
3161 };
3162
3163 return self.constInst(scope, inst.base.src, .{
3164 .ty = res_type,
3165 .val = Value.initPayload(val_payload),
3166 });
3167 }
3126}3168}
31273169
3128fn analyzeInstDeref(self: *Module, scope: *Scope, deref: *zir.Inst.UnOp) InnerError!*Inst {3170fn analyzeInstDeref(self: *Module, scope: *Scope, deref: *zir.Inst.UnOp) InnerError!*Inst {