authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2020-07-23 19:25:22+02:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2020-07-24 17:16:48+02:00
log470264a4f57bf667553678cd51d8c70945b96fe4
tree11a157fef20456cadfd0d55a648a88f43028e4de
parent97e92d868e0a4636b95e3a499c7de9f1b84b0ec6
signature Commit is signed but in an unrecognized format.

Restructuring and f32/f64 support


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

src-self-hosted/Module.zig+161-57
...@@ -3053,6 +3053,8 @@ fn analyzeInstArithmetic(self: *Module, scope: *Scope, inst: *zir.Inst.BinOp) In...@@ -3053,6 +3053,8 @@ fn analyzeInstArithmetic(self: *Module, scope: *Scope, inst: *zir.Inst.BinOp) In
30533053
3054 const instructions = &[_]*Inst{ lhs, rhs };3054 const instructions = &[_]*Inst{ lhs, rhs };
3055 const resolved_type = try self.resolvePeerTypes(scope, instructions);3055 const resolved_type = try self.resolvePeerTypes(scope, instructions);
3056 const casted_lhs = try self.coerce(scope, resolved_type, lhs);
3057 const casted_rhs = try self.coerce(scope, resolved_type, rhs);
30563058
3057 const scalar_type = if (resolved_type.zigTypeTag() == .Vector)3059 const scalar_type = if (resolved_type.zigTypeTag() == .Vector)
3058 resolved_type.elemType()3060 resolved_type.elemType()
...@@ -3083,8 +3085,8 @@ fn analyzeInstArithmetic(self: *Module, scope: *Scope, inst: *zir.Inst.BinOp) In...@@ -3083,8 +3085,8 @@ fn analyzeInstArithmetic(self: *Module, scope: *Scope, inst: *zir.Inst.BinOp) In
3083 return self.fail(scope, inst.base.src, "invalid operands to binary expression: '{}' and '{}'", .{ @tagName(lhs.ty.zigTypeTag()), @tagName(rhs.ty.zigTypeTag()) });3085 return self.fail(scope, inst.base.src, "invalid operands to binary expression: '{}' and '{}'", .{ @tagName(lhs.ty.zigTypeTag()), @tagName(rhs.ty.zigTypeTag()) });
3084 }3086 }
30853087
3086 if (lhs.value()) |lhs_val| {3088 if (casted_lhs.value()) |lhs_val| {
3087 if (rhs.value()) |rhs_val| {3089 if (casted_rhs.value()) |rhs_val| {
3088 return self.analyzeInstScalar(scope, scalar_type, inst, lhs_val, rhs_val);3090 return self.analyzeInstScalar(scope, scalar_type, inst, lhs_val, rhs_val);
3089 }3091 }
3090 }3092 }
...@@ -3096,26 +3098,7 @@ fn analyzeInstArithmetic(self: *Module, scope: *Scope, inst: *zir.Inst.BinOp) In...@@ -3096,26 +3098,7 @@ fn analyzeInstArithmetic(self: *Module, scope: *Scope, inst: *zir.Inst.BinOp) In
3096 else => return self.fail(scope, inst.base.src, "TODO implement arithmetic for operand '{}''", .{@tagName(inst.base.tag)}),3098 else => return self.fail(scope, inst.base.src, "TODO implement arithmetic for operand '{}''", .{@tagName(inst.base.tag)}),
3097 };3099 };
30983100
3099 if (is_float) {3101 return self.addBinOp(b, inst.base.src, scalar_type, ir_tag, casted_lhs, casted_rhs);
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);
3119}3102}
31203103
3121/// Analyzes operands that are known at comptime3104/// Analyzes operands that are known at comptime
...@@ -3128,43 +3111,30 @@ fn analyzeInstScalar(self: *Module, scope: *Scope, res_type: Type, inst: *zir.In...@@ -3128,43 +3111,30 @@ fn analyzeInstScalar(self: *Module, scope: *Scope, res_type: Type, inst: *zir.In
3128 .val = lhs_val,3111 .val = lhs_val,
3129 });3112 });
3130 }3113 }
3114 const is_int = res_type.isInt() or res_type.zigTypeTag() == .ComptimeInt;
31313115
3132 if (lhs_val.isFloat() or res_type.tag() == .comptime_float) {3116 const value = try switch (inst.base.tag) {
3133 return self.fail(scope, inst.base.src, "TODO implement arithmetic for floats", .{});3117 .add => blk: {
3134 } else {3118 const val = if (is_int)
3135 // TODO is this a performance issue? maybe we should try the operation without3119 bigIntAdd(scope.arena(), lhs_val, rhs_val)
3136 // resorting to BigInt first.3120 else
3137 var lhs_space: Value.BigIntSpace = undefined;3121 floatAdd(self.target(), scope.arena(), res_type, lhs_val, rhs_val);
3138 var rhs_space: Value.BigIntSpace = undefined;3122 break :blk val;
3139 const lhs_bigint = lhs_val.toBigInt(&lhs_space);3123 },
3140 const rhs_bigint = rhs_val.toBigInt(&rhs_space);3124 .sub => blk: {
3141 const limbs = try scope.arena().alloc(3125 const val = if (is_int)
3142 std.math.big.Limb,3126 bigIntSub(scope.arena(), lhs_val, rhs_val)
3143 std.math.max(lhs_bigint.limbs.len, rhs_bigint.limbs.len) + 1,3127 else
3144 );3128 floatSub(self.target(), scope.arena(), res_type, lhs_val, rhs_val);
3145 var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };3129 break :blk val;
3146 switch (inst.base.tag) {3130 },
3147 .add => result_bigint.add(lhs_bigint, rhs_bigint),3131 else => return self.fail(scope, inst.base.src, "TODO Implement arithmetic operand '{}'", .{@tagName(inst.base.tag)}),
3148 .sub => result_bigint.sub(lhs_bigint, rhs_bigint),3132 };
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 };
31623133
3163 return self.constInst(scope, inst.base.src, .{3134 return self.constInst(scope, inst.base.src, .{
3164 .ty = res_type,3135 .ty = res_type,
3165 .val = Value.initPayload(val_payload),3136 .val = value,
3166 });3137 });
3167 }
3168}3138}
31693139
3170fn analyzeInstDeref(self: *Module, scope: *Scope, deref: *zir.Inst.UnOp) InnerError!*Inst {3140fn analyzeInstDeref(self: *Module, scope: *Scope, deref: *zir.Inst.UnOp) InnerError!*Inst {
...@@ -3586,6 +3556,18 @@ fn resolvePeerTypes(self: *Module, scope: *Scope, instructions: []*Inst) !Type {...@@ -3586,6 +3556,18 @@ fn resolvePeerTypes(self: *Module, scope: *Scope, instructions: []*Inst) !Type {
3586 prev_inst = next_inst;3556 prev_inst = next_inst;
3587 continue;3557 continue;
3588 }3558 }
3559 if (prev_inst.ty.isInt() and next_inst.ty.isInt()) {
3560 if (prev_inst.ty.intInfo(self.target()).bits < next_inst.ty.intInfo(self.target()).bits) {
3561 prev_inst = next_inst;
3562 }
3563 continue;
3564 }
3565 if (prev_inst.ty.isFloat() and next_inst.ty.isFloat()) {
3566 if (prev_inst.ty.floatBits(self.target()) < next_inst.ty.floatBits(self.target())) {
3567 prev_inst = next_inst;
3568 }
3569 continue;
3570 }
35893571
3590 // TODO error notes pointing out each type3572 // TODO error notes pointing out each type
3591 return self.fail(scope, next_inst.src, "incompatible types: '{}' and '{}'", .{ prev_inst.ty, next_inst.ty });3573 return self.fail(scope, next_inst.src, "incompatible types: '{}' and '{}'", .{ prev_inst.ty, next_inst.ty });
...@@ -3836,3 +3818,125 @@ pub const ErrorMsg = struct {...@@ -3836,3 +3818,125 @@ pub const ErrorMsg = struct {
3836fn srcHashEql(a: std.zig.SrcHash, b: std.zig.SrcHash) bool {3818fn srcHashEql(a: std.zig.SrcHash, b: std.zig.SrcHash) bool {
3837 return @bitCast(u128, a) == @bitCast(u128, b);3819 return @bitCast(u128, a) == @bitCast(u128, b);
3838}3820}
3821
3822fn bigIntAdd(allocator: *Allocator, lhs: Value, rhs: Value) !Value {
3823 // TODO is this a performance issue? maybe we should try the operation without
3824 // resorting to BigInt first.
3825 var lhs_space: Value.BigIntSpace = undefined;
3826 var rhs_space: Value.BigIntSpace = undefined;
3827 const lhs_bigint = lhs.toBigInt(&lhs_space);
3828 const rhs_bigint = rhs.toBigInt(&rhs_space);
3829 const limbs = try allocator.alloc(
3830 std.math.big.Limb,
3831 std.math.max(lhs_bigint.limbs.len, rhs_bigint.limbs.len) + 1,
3832 );
3833 var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };
3834 result_bigint.add(lhs_bigint, rhs_bigint);
3835 const result_limbs = result_bigint.limbs[0..result_bigint.len];
3836
3837 const val_payload = if (result_bigint.positive) blk: {
3838 const val_payload = try allocator.create(Value.Payload.IntBigPositive);
3839 val_payload.* = .{ .limbs = result_limbs };
3840 break :blk &val_payload.base;
3841 } else blk: {
3842 const val_payload = try allocator.create(Value.Payload.IntBigNegative);
3843 val_payload.* = .{ .limbs = result_limbs };
3844 break :blk &val_payload.base;
3845 };
3846
3847 return Value.initPayload(val_payload);
3848}
3849
3850fn bigIntSub(allocator: *Allocator, lhs: Value, rhs: Value) !Value {
3851 // TODO is this a performance issue? maybe we should try the operation without
3852 // resorting to BigInt first.
3853 var lhs_space: Value.BigIntSpace = undefined;
3854 var rhs_space: Value.BigIntSpace = undefined;
3855 const lhs_bigint = lhs.toBigInt(&lhs_space);
3856 const rhs_bigint = rhs.toBigInt(&rhs_space);
3857 const limbs = try allocator.alloc(
3858 std.math.big.Limb,
3859 std.math.max(lhs_bigint.limbs.len, rhs_bigint.limbs.len) + 1,
3860 );
3861 var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };
3862 result_bigint.sub(lhs_bigint, rhs_bigint);
3863 const result_limbs = result_bigint.limbs[0..result_bigint.len];
3864
3865 const val_payload = if (result_bigint.positive) blk: {
3866 const val_payload = try allocator.create(Value.Payload.IntBigPositive);
3867 val_payload.* = .{ .limbs = result_limbs };
3868 break :blk &val_payload.base;
3869 } else blk: {
3870 const val_payload = try allocator.create(Value.Payload.IntBigNegative);
3871 val_payload.* = .{ .limbs = result_limbs };
3872 break :blk &val_payload.base;
3873 };
3874
3875 return Value.initPayload(val_payload);
3876}
3877
3878fn floatAdd(cur_target: Target, allocator: *Allocator, float_type: Type, lhs: Value, rhs: Value) !Value {
3879 var bit_count = switch (float_type.tag()) {
3880 .comptime_float => 128,
3881 else => float_type.floatBits(cur_target),
3882 };
3883
3884 const val_payload = switch (bit_count) {
3885 16 => {
3886 @panic("TODO soft float");
3887 },
3888 32 => blk: {
3889 const lhs_val = lhs.toFloat(f32);
3890 const rhs_val = rhs.toFloat(f32);
3891 const val_payload = try allocator.create(Value.Payload.Float_32);
3892 val_payload.* = .{ .val = lhs_val + rhs_val };
3893 break :blk &val_payload.base;
3894 },
3895 64 => blk: {
3896 const lhs_val = lhs.toFloat(f64);
3897 const rhs_val = rhs.toFloat(f64);
3898 const val_payload = try allocator.create(Value.Payload.Float_64);
3899 val_payload.* = .{ .val = lhs_val + rhs_val };
3900 break :blk &val_payload.base;
3901 },
3902 128 => blk: {
3903 @panic("TODO Big float");
3904 },
3905 else => unreachable,
3906 };
3907
3908 return Value.initPayload(val_payload);
3909}
3910
3911fn floatSub(cur_target: Target, allocator: *Allocator, float_type: Type, lhs: Value, rhs: Value) !Value {
3912 var bit_count = switch (float_type.tag()) {
3913 .comptime_float => 128,
3914 else => float_type.floatBits(cur_target),
3915 };
3916
3917 const val_payload = switch (bit_count) {
3918 16 => {
3919 @panic("TODO soft float");
3920 },
3921 32 => blk: {
3922 const lhs_val = lhs.toFloat(f32);
3923 const rhs_val = rhs.toFloat(f32);
3924 const val_payload = try allocator.create(Value.Payload.Float_32);
3925 val_payload.* = .{ .val = lhs_val - rhs_val };
3926 break :blk &val_payload.base;
3927 },
3928 64 => blk: {
3929 const lhs_val = lhs.toFloat(f64);
3930 const rhs_val = rhs.toFloat(f64);
3931 const val_payload = try allocator.create(Value.Payload.Float_64);
3932 val_payload.* = .{ .val = lhs_val - rhs_val };
3933 break :blk &val_payload.base;
3934 },
3935 128 => blk: {
3936 @panic("TODO Big float");
3937 },
3938 else => unreachable,
3939 };
3940
3941 return Value.initPayload(val_payload);
3942}