authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-07-21 22:35:05+00:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2020-07-21 22:35:05+00:00
log25a01a16e0eb729857f8e9a0a87bd0b8e9da301b
tree4f6607c2f58751a0e6c8cede44f8a6b784501714
parent68e0632aa531b33669bfdda374675aa26e91b40f
parentdd8929738876544d9b83c55df6e2ee3a491298ca
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #5905 from Vexu/stage2-float

Stage2: floats

9 files changed, 459 insertions(+), 90 deletions(-)

build.zig+2
...@@ -13,6 +13,7 @@ const InstallDirectoryOptions = std.build.InstallDirectoryOptions;...@@ -13,6 +13,7 @@ const InstallDirectoryOptions = std.build.InstallDirectoryOptions;
13pub fn build(b: *Builder) !void {13pub fn build(b: *Builder) !void {
14 b.setPreferredReleaseMode(.ReleaseFast);14 b.setPreferredReleaseMode(.ReleaseFast);
15 const mode = b.standardReleaseOptions();15 const mode = b.standardReleaseOptions();
16 const target = b.standardTargetOptions(.{});
1617
17 var docgen_exe = b.addExecutable("docgen", "doc/docgen.zig");18 var docgen_exe = b.addExecutable("docgen", "doc/docgen.zig");
1819
...@@ -54,6 +55,7 @@ pub fn build(b: *Builder) !void {...@@ -54,6 +55,7 @@ pub fn build(b: *Builder) !void {
54 if (!only_install_lib_files) {55 if (!only_install_lib_files) {
55 var exe = b.addExecutable("zig", "src-self-hosted/main.zig");56 var exe = b.addExecutable("zig", "src-self-hosted/main.zig");
56 exe.setBuildMode(mode);57 exe.setBuildMode(mode);
58 exe.setTarget(target);
57 test_step.dependOn(&exe.step);59 test_step.dependOn(&exe.step);
58 b.default_step.dependOn(&exe.step);60 b.default_step.dependOn(&exe.step);
5961
src-self-hosted/Module.zig+109-28
...@@ -2352,6 +2352,7 @@ fn analyzeInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*In...@@ -2352,6 +2352,7 @@ fn analyzeInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*In
2352 .fntype => return self.analyzeInstFnType(scope, old_inst.castTag(.fntype).?),2352 .fntype => return self.analyzeInstFnType(scope, old_inst.castTag(.fntype).?),
2353 .intcast => return self.analyzeInstIntCast(scope, old_inst.castTag(.intcast).?),2353 .intcast => return self.analyzeInstIntCast(scope, old_inst.castTag(.intcast).?),
2354 .bitcast => return self.analyzeInstBitCast(scope, old_inst.castTag(.bitcast).?),2354 .bitcast => return self.analyzeInstBitCast(scope, old_inst.castTag(.bitcast).?),
2355 .floatcast => return self.analyzeInstFloatCast(scope, old_inst.castTag(.floatcast).?),
2355 .elemptr => return self.analyzeInstElemPtr(scope, old_inst.castTag(.elemptr).?),2356 .elemptr => return self.analyzeInstElemPtr(scope, old_inst.castTag(.elemptr).?),
2356 .add => return self.analyzeInstAdd(scope, old_inst.castTag(.add).?),2357 .add => return self.analyzeInstAdd(scope, old_inst.castTag(.add).?),
2357 .sub => return self.analyzeInstSub(scope, old_inst.castTag(.sub).?),2358 .sub => return self.analyzeInstSub(scope, old_inst.castTag(.sub).?),
...@@ -2796,16 +2797,16 @@ fn analyzeInstFieldPtr(self: *Module, scope: *Scope, fieldptr: *zir.Inst.FieldPt...@@ -2796,16 +2797,16 @@ fn analyzeInstFieldPtr(self: *Module, scope: *Scope, fieldptr: *zir.Inst.FieldPt
2796 }2797 }
2797}2798}
27982799
2799fn analyzeInstIntCast(self: *Module, scope: *Scope, intcast: *zir.Inst.IntCast) InnerError!*Inst {2800fn analyzeInstIntCast(self: *Module, scope: *Scope, inst: *zir.Inst.IntCast) InnerError!*Inst {
2800 const dest_type = try self.resolveType(scope, intcast.positionals.dest_type);2801 const dest_type = try self.resolveType(scope, inst.positionals.dest_type);
2801 const new_inst = try self.resolveInst(scope, intcast.positionals.value);2802 const operand = try self.resolveInst(scope, inst.positionals.operand);
28022803
2803 const dest_is_comptime_int = switch (dest_type.zigTypeTag()) {2804 const dest_is_comptime_int = switch (dest_type.zigTypeTag()) {
2804 .ComptimeInt => true,2805 .ComptimeInt => true,
2805 .Int => false,2806 .Int => false,
2806 else => return self.fail(2807 else => return self.fail(
2807 scope,2808 scope,
2808 intcast.positionals.dest_type.src,2809 inst.positionals.dest_type.src,
2809 "expected integer type, found '{}'",2810 "expected integer type, found '{}'",
2810 .{2811 .{
2811 dest_type,2812 dest_type,
...@@ -2813,21 +2814,23 @@ fn analyzeInstIntCast(self: *Module, scope: *Scope, intcast: *zir.Inst.IntCast)...@@ -2813,21 +2814,23 @@ fn analyzeInstIntCast(self: *Module, scope: *Scope, intcast: *zir.Inst.IntCast)
2813 ),2814 ),
2814 };2815 };
28152816
2816 switch (new_inst.ty.zigTypeTag()) {2817 switch (operand.ty.zigTypeTag()) {
2817 .ComptimeInt, .Int => {},2818 .ComptimeInt, .Int => {},
2818 else => return self.fail(2819 else => return self.fail(
2819 scope,2820 scope,
2820 intcast.positionals.value.src,2821 inst.positionals.operand.src,
2821 "expected integer type, found '{}'",2822 "expected integer type, found '{}'",
2822 .{new_inst.ty},2823 .{operand.ty},
2823 ),2824 ),
2824 }2825 }
28252826
2826 if (dest_is_comptime_int or new_inst.value() != null) {2827 if (operand.value() != null) {
2827 return self.coerce(scope, dest_type, new_inst);2828 return self.coerce(scope, dest_type, operand);
2829 } else if (dest_is_comptime_int) {
2830 return self.fail(scope, inst.base.src, "unable to cast runtime value to 'comptime_int'", .{});
2828 }2831 }
28292832
2830 return self.fail(scope, intcast.base.src, "TODO implement analyze widen or shorten int", .{});2833 return self.fail(scope, inst.base.src, "TODO implement analyze widen or shorten int", .{});
2831}2834}
28322835
2833fn analyzeInstBitCast(self: *Module, scope: *Scope, inst: *zir.Inst.BitCast) InnerError!*Inst {2836fn analyzeInstBitCast(self: *Module, scope: *Scope, inst: *zir.Inst.BitCast) InnerError!*Inst {
...@@ -2836,6 +2839,42 @@ fn analyzeInstBitCast(self: *Module, scope: *Scope, inst: *zir.Inst.BitCast) Inn...@@ -2836,6 +2839,42 @@ fn analyzeInstBitCast(self: *Module, scope: *Scope, inst: *zir.Inst.BitCast) Inn
2836 return self.bitcast(scope, dest_type, operand);2839 return self.bitcast(scope, dest_type, operand);
2837}2840}
28382841
2842fn analyzeInstFloatCast(self: *Module, scope: *Scope, inst: *zir.Inst.FloatCast) InnerError!*Inst {
2843 const dest_type = try self.resolveType(scope, inst.positionals.dest_type);
2844 const operand = try self.resolveInst(scope, inst.positionals.operand);
2845
2846 const dest_is_comptime_float = switch (dest_type.zigTypeTag()) {
2847 .ComptimeFloat => true,
2848 .Float => false,
2849 else => return self.fail(
2850 scope,
2851 inst.positionals.dest_type.src,
2852 "expected float type, found '{}'",
2853 .{
2854 dest_type,
2855 },
2856 ),
2857 };
2858
2859 switch (operand.ty.zigTypeTag()) {
2860 .ComptimeFloat, .Float, .ComptimeInt => {},
2861 else => return self.fail(
2862 scope,
2863 inst.positionals.operand.src,
2864 "expected float type, found '{}'",
2865 .{operand.ty},
2866 ),
2867 }
2868
2869 if (operand.value() != null) {
2870 return self.coerce(scope, dest_type, operand);
2871 } else if (dest_is_comptime_float) {
2872 return self.fail(scope, inst.base.src, "unable to cast runtime value to 'comptime_float'", .{});
2873 }
2874
2875 return self.fail(scope, inst.base.src, "TODO implement analyze widen or shorten float", .{});
2876}
2877
2839fn analyzeInstElemPtr(self: *Module, scope: *Scope, inst: *zir.Inst.ElemPtr) InnerError!*Inst {2878fn analyzeInstElemPtr(self: *Module, scope: *Scope, inst: *zir.Inst.ElemPtr) InnerError!*Inst {
2840 const array_ptr = try self.resolveInst(scope, inst.positionals.array_ptr);2879 const array_ptr = try self.resolveInst(scope, inst.positionals.array_ptr);
2841 const uncasted_index = try self.resolveInst(scope, inst.positionals.index);2880 const uncasted_index = try self.resolveInst(scope, inst.positionals.index);
...@@ -3358,6 +3397,14 @@ fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst {...@@ -3358,6 +3397,14 @@ fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst {
3358 return self.bitcast(scope, dest_type, inst);3397 return self.bitcast(scope, dest_type, inst);
3359 }3398 }
33603399
3400 // undefined to anything
3401 if (inst.value()) |val| {
3402 if (val.isUndef() or inst.ty.zigTypeTag() == .Undefined) {
3403 return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = val });
3404 }
3405 }
3406 assert(inst.ty.zigTypeTag() != .Undefined);
3407
3361 // *[N]T to []T3408 // *[N]T to []T
3362 if (inst.ty.isSinglePointer() and dest_type.isSlice() and3409 if (inst.ty.isSinglePointer() and dest_type.isSlice() and
3363 (!inst.ty.pointerIsConst() or dest_type.pointerIsConst()))3410 (!inst.ty.pointerIsConst() or dest_type.pointerIsConst()))
...@@ -3371,31 +3418,65 @@ fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst {...@@ -3371,31 +3418,65 @@ fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst {
3371 }3418 }
3372 }3419 }
33733420
3374 // comptime_int to fixed-width integer3421 // comptime known number to other number
3375 if (inst.ty.zigTypeTag() == .ComptimeInt and dest_type.zigTypeTag() == .Int) {3422 if (inst.value()) |val| {
3376 // The representation is already correct; we only need to make sure it fits in the destination type.3423 const src_zig_tag = inst.ty.zigTypeTag();
3377 const val = inst.value().?; // comptime_int always has comptime known value3424 const dst_zig_tag = dest_type.zigTypeTag();
3378 if (!val.intFitsInType(dest_type, self.target())) {3425
3379 return self.fail(scope, inst.src, "type {} cannot represent integer value {}", .{ inst.ty, val });3426 if (dst_zig_tag == .ComptimeInt or dst_zig_tag == .Int) {
3427 if (src_zig_tag == .Float or src_zig_tag == .ComptimeFloat) {
3428 if (val.floatHasFraction()) {
3429 return self.fail(scope, inst.src, "fractional component prevents float value {} from being casted to type '{}'", .{ val, inst.ty });
3430 }
3431 return self.fail(scope, inst.src, "TODO float to int", .{});
3432 } else if (src_zig_tag == .Int or src_zig_tag == .ComptimeInt) {
3433 if (!val.intFitsInType(dest_type, self.target())) {
3434 return self.fail(scope, inst.src, "type {} cannot represent integer value {}", .{ inst.ty, val });
3435 }
3436 return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = val });
3437 }
3438 } else if (dst_zig_tag == .ComptimeFloat or dst_zig_tag == .Float) {
3439 if (src_zig_tag == .Float or src_zig_tag == .ComptimeFloat) {
3440 const res = val.floatCast(scope.arena(), dest_type, self.target()) catch |err| switch (err) {
3441 error.Overflow => return self.fail(
3442 scope,
3443 inst.src,
3444 "cast of value {} to type '{}' loses information",
3445 .{ val, dest_type },
3446 ),
3447 error.OutOfMemory => return error.OutOfMemory,
3448 };
3449 return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = res });
3450 } else if (src_zig_tag == .Int or src_zig_tag == .ComptimeInt) {
3451 return self.fail(scope, inst.src, "TODO int to float", .{});
3452 }
3380 }3453 }
3381 return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = val });
3382 }3454 }
33833455
3384 // integer widening3456 // integer widening
3385 if (inst.ty.zigTypeTag() == .Int and dest_type.zigTypeTag() == .Int) {3457 if (inst.ty.zigTypeTag() == .Int and dest_type.zigTypeTag() == .Int) {
3458 assert(inst.value() == null); // handled above
3459
3386 const src_info = inst.ty.intInfo(self.target());3460 const src_info = inst.ty.intInfo(self.target());
3387 const dst_info = dest_type.intInfo(self.target());3461 const dst_info = dest_type.intInfo(self.target());
3388 if (src_info.signed == dst_info.signed and dst_info.bits >= src_info.bits) {3462 if ((src_info.signed == dst_info.signed and dst_info.bits >= src_info.bits) or
3389 if (inst.value()) |val| {3463 // small enough unsigned ints can get casted to large enough signed ints
3390 return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = val });3464 (src_info.signed and !dst_info.signed and dst_info.bits > src_info.bits))
3391 } else {3465 {
3392 return self.fail(scope, inst.src, "TODO implement runtime integer widening ({} to {})", .{3466 const b = try self.requireRuntimeBlock(scope, inst.src);
3393 inst.ty,3467 return self.addUnOp(b, inst.src, dest_type, .intcast, inst);
3394 dest_type,3468 }
3395 });3469 }
3396 }3470
3397 } else {3471 // float widening
3398 return self.fail(scope, inst.src, "TODO implement more int widening {} to {}", .{ inst.ty, dest_type });3472 if (inst.ty.zigTypeTag() == .Float and dest_type.zigTypeTag() == .Float) {
3473 assert(inst.value() == null); // handled above
3474
3475 const src_bits = inst.ty.floatBits(self.target());
3476 const dst_bits = dest_type.floatBits(self.target());
3477 if (dst_bits >= src_bits) {
3478 const b = try self.requireRuntimeBlock(scope, inst.src);
3479 return self.addUnOp(b, inst.src, dest_type, .floatcast, inst);
3399 }3480 }
3400 }3481 }
34013482
src-self-hosted/astgen.zig+56-25
...@@ -38,6 +38,8 @@ pub fn expr(mod: *Module, scope: *Scope, node: *ast.Node) InnerError!*zir.Inst {...@@ -38,6 +38,8 @@ pub fn expr(mod: *Module, scope: *Scope, node: *ast.Node) InnerError!*zir.Inst {
38 .Period => return field(mod, scope, node.castTag(.Period).?),38 .Period => return field(mod, scope, node.castTag(.Period).?),
39 .Deref => return deref(mod, scope, node.castTag(.Deref).?),39 .Deref => return deref(mod, scope, node.castTag(.Deref).?),
40 .BoolNot => return boolNot(mod, scope, node.castTag(.BoolNot).?),40 .BoolNot => return boolNot(mod, scope, node.castTag(.BoolNot).?),
41 .FloatLiteral => return floatLiteral(mod, scope, node.castTag(.FloatLiteral).?),
42 .UndefinedLiteral, .BoolLiteral, .NullLiteral => return primitiveLiteral(mod, scope, node),
41 else => return mod.failNode(scope, node, "TODO implement astgen.Expr for {}", .{@tagName(node.tag)}),43 else => return mod.failNode(scope, node, "TODO implement astgen.Expr for {}", .{@tagName(node.tag)}),
42 }44 }
43}45}
...@@ -323,7 +325,14 @@ fn identifier(mod: *Module, scope: *Scope, ident: *ast.Node.Identifier) InnerErr...@@ -323,7 +325,14 @@ fn identifier(mod: *Module, scope: *Scope, ident: *ast.Node.Identifier) InnerErr
323 16 => if (is_signed) Value.initTag(.i16_type) else Value.initTag(.u16_type),325 16 => if (is_signed) Value.initTag(.i16_type) else Value.initTag(.u16_type),
324 32 => if (is_signed) Value.initTag(.i32_type) else Value.initTag(.u32_type),326 32 => if (is_signed) Value.initTag(.i32_type) else Value.initTag(.u32_type),
325 64 => if (is_signed) Value.initTag(.i64_type) else Value.initTag(.u64_type),327 64 => if (is_signed) Value.initTag(.i64_type) else Value.initTag(.u64_type),
326 else => return mod.failNode(scope, &ident.base, "TODO implement arbitrary integer bitwidth types", .{}),328 else => {
329 const int_type_payload = try scope.arena().create(Value.Payload.IntType);
330 int_type_payload.* = .{ .signed = is_signed, .bits = bit_count };
331 return mod.addZIRInstConst(scope, src, .{
332 .ty = Type.initTag(.comptime_int),
333 .val = Value.initPayload(&int_type_payload.base),
334 });
335 },
327 };336 };
328 return mod.addZIRInstConst(scope, src, .{337 return mod.addZIRInstConst(scope, src, .{
329 .ty = Type.initTag(.type),338 .ty = Type.initTag(.type),
...@@ -405,6 +414,52 @@ fn integerLiteral(mod: *Module, scope: *Scope, int_lit: *ast.Node.IntegerLiteral...@@ -405,6 +414,52 @@ fn integerLiteral(mod: *Module, scope: *Scope, int_lit: *ast.Node.IntegerLiteral
405 }414 }
406}415}
407416
417fn floatLiteral(mod: *Module, scope: *Scope, float_lit: *ast.Node.FloatLiteral) InnerError!*zir.Inst {
418 const arena = scope.arena();
419 const tree = scope.tree();
420 const bytes = tree.tokenSlice(float_lit.token);
421 if (bytes.len > 2 and bytes[1] == 'x') {
422 return mod.failTok(scope, float_lit.token, "TODO hex floats", .{});
423 }
424
425 const val = std.fmt.parseFloat(f128, bytes) catch |e| switch (e) {
426 error.InvalidCharacter => unreachable, // validated by tokenizer
427 };
428 const float_payload = try arena.create(Value.Payload.Float_128);
429 float_payload.* = .{ .val = val };
430 const src = tree.token_locs[float_lit.token].start;
431 return mod.addZIRInstConst(scope, src, .{
432 .ty = Type.initTag(.comptime_float),
433 .val = Value.initPayload(&float_payload.base),
434 });
435}
436
437fn primitiveLiteral(mod: *Module, scope: *Scope, node: *ast.Node) InnerError!*zir.Inst {
438 const arena = scope.arena();
439 const tree = scope.tree();
440 const src = tree.token_locs[node.firstToken()].start;
441
442 if (node.cast(ast.Node.BoolLiteral)) |bool_node| {
443 return mod.addZIRInstConst(scope, src, .{
444 .ty = Type.initTag(.bool),
445 .val = if (tree.token_ids[bool_node.token] == .Keyword_true)
446 Value.initTag(.bool_true)
447 else
448 Value.initTag(.bool_false),
449 });
450 } else if (node.tag == .UndefinedLiteral) {
451 return mod.addZIRInstConst(scope, src, .{
452 .ty = Type.initTag(.@"undefined"),
453 .val = Value.initTag(.undef),
454 });
455 } else if (node.tag == .NullLiteral) {
456 return mod.addZIRInstConst(scope, src, .{
457 .ty = Type.initTag(.@"null"),
458 .val = Value.initTag(.null_value),
459 });
460 } else unreachable;
461}
462
408fn assembly(mod: *Module, scope: *Scope, asm_node: *ast.Node.Asm) InnerError!*zir.Inst {463fn assembly(mod: *Module, scope: *Scope, asm_node: *ast.Node.Asm) InnerError!*zir.Inst {
409 if (asm_node.outputs.len != 0) {464 if (asm_node.outputs.len != 0) {
410 return mod.failNode(scope, &asm_node.base, "TODO implement asm with an output", .{});465 return mod.failNode(scope, &asm_node.base, "TODO implement asm with an output", .{});
...@@ -534,30 +589,6 @@ fn getSimplePrimitiveValue(name: []const u8) ?TypedValue {...@@ -534,30 +589,6 @@ fn getSimplePrimitiveValue(name: []const u8) ?TypedValue {
534 .val = Value.initTag(tag),589 .val = Value.initTag(tag),
535 };590 };
536 }591 }
537 if (mem.eql(u8, name, "null")) {
538 return TypedValue{
539 .ty = Type.initTag(.@"null"),
540 .val = Value.initTag(.null_value),
541 };
542 }
543 if (mem.eql(u8, name, "undefined")) {
544 return TypedValue{
545 .ty = Type.initTag(.@"undefined"),
546 .val = Value.initTag(.undef),
547 };
548 }
549 if (mem.eql(u8, name, "true")) {
550 return TypedValue{
551 .ty = Type.initTag(.bool),
552 .val = Value.initTag(.bool_true),
553 };
554 }
555 if (mem.eql(u8, name, "false")) {
556 return TypedValue{
557 .ty = Type.initTag(.bool),
558 .val = Value.initTag(.bool_false),
559 };
560 }
561 return null;592 return null;
562}593}
563594
src-self-hosted/codegen.zig+20
...@@ -459,6 +459,26 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -459,6 +459,26 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
459 .sub => return self.genSub(inst.castTag(.sub).?),459 .sub => return self.genSub(inst.castTag(.sub).?),
460 .unreach => return MCValue{ .unreach = {} },460 .unreach => return MCValue{ .unreach = {} },
461 .not => return self.genNot(inst.castTag(.not).?),461 .not => return self.genNot(inst.castTag(.not).?),
462 .floatcast => return self.genFloatCast(inst.castTag(.floatcast).?),
463 .intcast => return self.genIntCast(inst.castTag(.intcast).?),
464 }
465 }
466
467 fn genFloatCast(self: *Self, inst: *ir.Inst.UnOp) !MCValue {
468 // No side effects, so if it's unreferenced, do nothing.
469 if (inst.base.isUnused())
470 return MCValue.dead;
471 switch (arch) {
472 else => return self.fail(inst.base.src, "TODO implement floatCast for {}", .{self.target.cpu.arch}),
473 }
474 }
475
476 fn genIntCast(self: *Self, inst: *ir.Inst.UnOp) !MCValue {
477 // No side effects, so if it's unreferenced, do nothing.
478 if (inst.base.isUnused())
479 return MCValue.dead;
480 switch (arch) {
481 else => return self.fail(inst.base.src, "TODO implement intCast for {}", .{self.target.cpu.arch}),
462 }482 }
463 }483 }
464484
src-self-hosted/ir.zig+4
...@@ -71,6 +71,8 @@ pub const Inst = struct {...@@ -71,6 +71,8 @@ pub const Inst = struct {
71 sub,71 sub,
72 unreach,72 unreach,
73 not,73 not,
74 floatcast,
75 intcast,
7476
75 /// There is one-to-one correspondence between tag and type for now,77 /// There is one-to-one correspondence between tag and type for now,
76 /// but this will not always be the case. For example, binary operations78 /// but this will not always be the case. For example, binary operations
...@@ -89,6 +91,8 @@ pub const Inst = struct {...@@ -89,6 +91,8 @@ pub const Inst = struct {
89 .isnonnull,91 .isnonnull,
90 .isnull,92 .isnull,
91 .ptrtoint,93 .ptrtoint,
94 .floatcast,
95 .intcast,
92 => UnOp,96 => UnOp,
9397
94 .add,98 .add,
src-self-hosted/value.zig+211-18
...@@ -70,6 +70,7 @@ pub const Value = extern union {...@@ -70,6 +70,7 @@ pub const Value = extern union {
70 // After this, the tag requires a payload.70 // After this, the tag requires a payload.
7171
72 ty,72 ty,
73 int_type,
73 int_u64,74 int_u64,
74 int_i64,75 int_i64,
75 int_big_positive,76 int_big_positive,
...@@ -80,6 +81,10 @@ pub const Value = extern union {...@@ -80,6 +81,10 @@ pub const Value = extern union {
80 elem_ptr,81 elem_ptr,
81 bytes,82 bytes,
82 repeated, // the value is a value repeated some number of times83 repeated, // the value is a value repeated some number of times
84 float_16,
85 float_32,
86 float_64,
87 float_128,
8388
84 pub const last_no_payload_tag = Tag.bool_false;89 pub const last_no_payload_tag = Tag.bool_false;
85 pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;90 pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
...@@ -174,6 +179,7 @@ pub const Value = extern union {...@@ -174,6 +179,7 @@ pub const Value = extern union {
174 };179 };
175 return Value{ .ptr_otherwise = &new_payload.base };180 return Value{ .ptr_otherwise = &new_payload.base };
176 },181 },
182 .int_type => return self.copyPayloadShallow(allocator, Payload.IntType),
177 .int_u64 => return self.copyPayloadShallow(allocator, Payload.Int_u64),183 .int_u64 => return self.copyPayloadShallow(allocator, Payload.Int_u64),
178 .int_i64 => return self.copyPayloadShallow(allocator, Payload.Int_i64),184 .int_i64 => return self.copyPayloadShallow(allocator, Payload.Int_i64),
179 .int_big_positive => {185 .int_big_positive => {
...@@ -213,6 +219,10 @@ pub const Value = extern union {...@@ -213,6 +219,10 @@ pub const Value = extern union {
213 };219 };
214 return Value{ .ptr_otherwise = &new_payload.base };220 return Value{ .ptr_otherwise = &new_payload.base };
215 },221 },
222 .float_16 => return self.copyPayloadShallow(allocator, Payload.Float_16),
223 .float_32 => return self.copyPayloadShallow(allocator, Payload.Float_32),
224 .float_64 => return self.copyPayloadShallow(allocator, Payload.Float_64),
225 .float_128 => return self.copyPayloadShallow(allocator, Payload.Float_128),
216 }226 }
217 }227 }
218228
...@@ -279,6 +289,13 @@ pub const Value = extern union {...@@ -279,6 +289,13 @@ pub const Value = extern union {
279 .bool_true => return out_stream.writeAll("true"),289 .bool_true => return out_stream.writeAll("true"),
280 .bool_false => return out_stream.writeAll("false"),290 .bool_false => return out_stream.writeAll("false"),
281 .ty => return val.cast(Payload.Ty).?.ty.format("", options, out_stream),291 .ty => return val.cast(Payload.Ty).?.ty.format("", options, out_stream),
292 .int_type => {
293 const int_type = val.cast(Payload.IntType).?;
294 return out_stream.print("{}{}", .{
295 if (int_type.signed) "s" else "u",
296 int_type.bits,
297 });
298 },
282 .int_u64 => return std.fmt.formatIntValue(val.cast(Payload.Int_u64).?.int, "", options, out_stream),299 .int_u64 => return std.fmt.formatIntValue(val.cast(Payload.Int_u64).?.int, "", options, out_stream),
283 .int_i64 => return std.fmt.formatIntValue(val.cast(Payload.Int_i64).?.int, "", options, out_stream),300 .int_i64 => return std.fmt.formatIntValue(val.cast(Payload.Int_i64).?.int, "", options, out_stream),
284 .int_big_positive => return out_stream.print("{}", .{val.cast(Payload.IntBigPositive).?.asBigInt()}),301 .int_big_positive => return out_stream.print("{}", .{val.cast(Payload.IntBigPositive).?.asBigInt()}),
...@@ -300,6 +317,10 @@ pub const Value = extern union {...@@ -300,6 +317,10 @@ pub const Value = extern union {
300 try out_stream.writeAll("(repeated) ");317 try out_stream.writeAll("(repeated) ");
301 val = val.cast(Payload.Repeated).?.val;318 val = val.cast(Payload.Repeated).?.val;
302 },319 },
320 .float_16 => return out_stream.print("{}", .{val.cast(Payload.Float_16).?.val}),
321 .float_32 => return out_stream.print("{}", .{val.cast(Payload.Float_32).?.val}),
322 .float_64 => return out_stream.print("{}", .{val.cast(Payload.Float_64).?.val}),
323 .float_128 => return out_stream.print("{}", .{val.cast(Payload.Float_128).?.val}),
303 };324 };
304 }325 }
305326
...@@ -323,6 +344,7 @@ pub const Value = extern union {...@@ -323,6 +344,7 @@ pub const Value = extern union {
323 pub fn toType(self: Value) Type {344 pub fn toType(self: Value) Type {
324 return switch (self.tag()) {345 return switch (self.tag()) {
325 .ty => self.cast(Payload.Ty).?.ty,346 .ty => self.cast(Payload.Ty).?.ty,
347 .int_type => @panic("TODO int type to type"),
326348
327 .u8_type => Type.initTag(.u8),349 .u8_type => Type.initTag(.u8),
328 .i8_type => Type.initTag(.i8),350 .i8_type => Type.initTag(.i8),
...@@ -380,6 +402,10 @@ pub const Value = extern union {...@@ -380,6 +402,10 @@ pub const Value = extern union {
380 .elem_ptr,402 .elem_ptr,
381 .bytes,403 .bytes,
382 .repeated,404 .repeated,
405 .float_16,
406 .float_32,
407 .float_64,
408 .float_128,
383 => unreachable,409 => unreachable,
384 };410 };
385 }411 }
...@@ -388,6 +414,7 @@ pub const Value = extern union {...@@ -388,6 +414,7 @@ pub const Value = extern union {
388 pub fn toBigInt(self: Value, space: *BigIntSpace) BigIntConst {414 pub fn toBigInt(self: Value, space: *BigIntSpace) BigIntConst {
389 switch (self.tag()) {415 switch (self.tag()) {
390 .ty,416 .ty,
417 .int_type,
391 .u8_type,418 .u8_type,
392 .i8_type,419 .i8_type,
393 .u16_type,420 .u16_type,
...@@ -435,6 +462,10 @@ pub const Value = extern union {...@@ -435,6 +462,10 @@ pub const Value = extern union {
435 .bytes,462 .bytes,
436 .undef,463 .undef,
437 .repeated,464 .repeated,
465 .float_16,
466 .float_32,
467 .float_64,
468 .float_128,
438 => unreachable,469 => unreachable,
439470
440 .the_one_possible_value, // An integer with one possible value is always zero.471 .the_one_possible_value, // An integer with one possible value is always zero.
...@@ -455,6 +486,7 @@ pub const Value = extern union {...@@ -455,6 +486,7 @@ pub const Value = extern union {
455 pub fn toUnsignedInt(self: Value) u64 {486 pub fn toUnsignedInt(self: Value) u64 {
456 switch (self.tag()) {487 switch (self.tag()) {
457 .ty,488 .ty,
489 .int_type,
458 .u8_type,490 .u8_type,
459 .i8_type,491 .i8_type,
460 .u16_type,492 .u16_type,
...@@ -502,6 +534,10 @@ pub const Value = extern union {...@@ -502,6 +534,10 @@ pub const Value = extern union {
502 .bytes,534 .bytes,
503 .undef,535 .undef,
504 .repeated,536 .repeated,
537 .float_16,
538 .float_32,
539 .float_64,
540 .float_128,
505 => unreachable,541 => unreachable,
506542
507 .zero,543 .zero,
...@@ -518,11 +554,38 @@ pub const Value = extern union {...@@ -518,11 +554,38 @@ pub const Value = extern union {
518 }554 }
519 }555 }
520556
557 pub fn toBool(self: Value) bool {
558 return switch (self.tag()) {
559 .bool_true => true,
560 .bool_false, .zero => false,
561 else => unreachable,
562 };
563 }
564
565 /// Asserts that the value is a float or an integer.
566 pub fn toFloat(self: Value, comptime T: type) T {
567 return switch (self.tag()) {
568 .float_16 => @panic("TODO soft float"),
569 .float_32 => @floatCast(T, self.cast(Payload.Float_32).?.val),
570 .float_64 => @floatCast(T, self.cast(Payload.Float_64).?.val),
571 .float_128 => @floatCast(T, self.cast(Payload.Float_128).?.val),
572
573 .zero, .the_one_possible_value => 0,
574 .int_u64 => @intToFloat(T, self.cast(Payload.Int_u64).?.int),
575 // .int_i64 => @intToFloat(f128, self.cast(Payload.Int_i64).?.int),
576 .int_i64 => @panic("TODO lld: error: undefined symbol: __floatditf"),
577
578 .int_big_positive, .int_big_negative => @panic("big int to f128"),
579 else => unreachable,
580 };
581 }
582
521 /// Asserts the value is an integer and not undefined.583 /// Asserts the value is an integer and not undefined.
522 /// Returns the number of bits the value requires to represent stored in twos complement form.584 /// Returns the number of bits the value requires to represent stored in twos complement form.
523 pub fn intBitCountTwosComp(self: Value) usize {585 pub fn intBitCountTwosComp(self: Value) usize {
524 switch (self.tag()) {586 switch (self.tag()) {
525 .ty,587 .ty,
588 .int_type,
526 .u8_type,589 .u8_type,
527 .i8_type,590 .i8_type,
528 .u16_type,591 .u16_type,
...@@ -570,6 +633,10 @@ pub const Value = extern union {...@@ -570,6 +633,10 @@ pub const Value = extern union {
570 .bytes,633 .bytes,
571 .undef,634 .undef,
572 .repeated,635 .repeated,
636 .float_16,
637 .float_32,
638 .float_64,
639 .float_128,
573 => unreachable,640 => unreachable,
574641
575 .the_one_possible_value, // an integer with one possible value is always zero642 .the_one_possible_value, // an integer with one possible value is always zero
...@@ -596,6 +663,7 @@ pub const Value = extern union {...@@ -596,6 +663,7 @@ pub const Value = extern union {
596 pub fn intFitsInType(self: Value, ty: Type, target: Target) bool {663 pub fn intFitsInType(self: Value, ty: Type, target: Target) bool {
597 switch (self.tag()) {664 switch (self.tag()) {
598 .ty,665 .ty,
666 .int_type,
599 .u8_type,667 .u8_type,
600 .i8_type,668 .i8_type,
601 .u16_type,669 .u16_type,
...@@ -642,6 +710,10 @@ pub const Value = extern union {...@@ -642,6 +710,10 @@ pub const Value = extern union {
642 .elem_ptr,710 .elem_ptr,
643 .bytes,711 .bytes,
644 .repeated,712 .repeated,
713 .float_16,
714 .float_32,
715 .float_64,
716 .float_128,
645 => unreachable,717 => unreachable,
646718
647 .zero,719 .zero,
...@@ -701,10 +773,55 @@ pub const Value = extern union {...@@ -701,10 +773,55 @@ pub const Value = extern union {
701 }773 }
702 }774 }
703775
776 /// Converts an integer or a float to a float.
777 /// Returns `error.Overflow` if the value does not fit in the new type.
778 pub fn floatCast(self: Value, allocator: *Allocator, ty: Type, target: Target) !Value {
779 const dest_bit_count = switch (ty.tag()) {
780 .comptime_float => 128,
781 else => ty.floatBits(target),
782 };
783 switch (dest_bit_count) {
784 16, 32, 64, 128 => {},
785 else => std.debug.panic("TODO float cast bit count {}\n", .{dest_bit_count}),
786 }
787 if (ty.isInt()) {
788 @panic("TODO int to float");
789 }
790
791 switch (dest_bit_count) {
792 16 => {
793 @panic("TODO soft float");
794 // var res_payload = Value.Payload.Float_16{.val = self.toFloat(f16)};
795 // if (!self.eql(Value.initPayload(&res_payload.base)))
796 // return error.Overflow;
797 // return Value.initPayload(&res_payload.base).copy(allocator);
798 },
799 32 => {
800 var res_payload = Value.Payload.Float_32{.val = self.toFloat(f32)};
801 if (!self.eql(Value.initPayload(&res_payload.base)))
802 return error.Overflow;
803 return Value.initPayload(&res_payload.base).copy(allocator);
804 },
805 64 => {
806 var res_payload = Value.Payload.Float_64{.val = self.toFloat(f64)};
807 if (!self.eql(Value.initPayload(&res_payload.base)))
808 return error.Overflow;
809 return Value.initPayload(&res_payload.base).copy(allocator);
810 },
811 128 => {
812 const float_payload = try allocator.create(Value.Payload.Float_128);
813 float_payload.* = .{ .val = self.toFloat(f128) };
814 return Value.initPayload(&float_payload.base);
815 },
816 else => unreachable,
817 }
818 }
819
704 /// Asserts the value is a float820 /// Asserts the value is a float
705 pub fn floatHasFraction(self: Value) bool {821 pub fn floatHasFraction(self: Value) bool {
706 return switch (self.tag()) {822 return switch (self.tag()) {
707 .ty,823 .ty,
824 .int_type,
708 .u8_type,825 .u8_type,
709 .i8_type,826 .i8_type,
710 .u16_type,827 .u16_type,
...@@ -762,12 +879,19 @@ pub const Value = extern union {...@@ -762,12 +879,19 @@ pub const Value = extern union {
762 => unreachable,879 => unreachable,
763880
764 .zero => false,881 .zero => false,
882
883 .float_16 => @rem(self.cast(Payload.Float_16).?.val, 1) != 0,
884 .float_32 => @rem(self.cast(Payload.Float_32).?.val, 1) != 0,
885 .float_64 => @rem(self.cast(Payload.Float_64).?.val, 1) != 0,
886 // .float_128 => @rem(self.cast(Payload.Float_128).?.val, 1) != 0,
887 .float_128 => @panic("TODO lld: error: undefined symbol: fmodl"),
765 };888 };
766 }889 }
767890
768 pub fn orderAgainstZero(lhs: Value) std.math.Order {891 pub fn orderAgainstZero(lhs: Value) std.math.Order {
769 switch (lhs.tag()) {892 return switch (lhs.tag()) {
770 .ty,893 .ty,
894 .int_type,
771 .u8_type,895 .u8_type,
772 .i8_type,896 .i8_type,
773 .u16_type,897 .u16_type,
...@@ -820,27 +944,49 @@ pub const Value = extern union {...@@ -820,27 +944,49 @@ pub const Value = extern union {
820 .zero,944 .zero,
821 .the_one_possible_value, // an integer with one possible value is always zero945 .the_one_possible_value, // an integer with one possible value is always zero
822 .bool_false,946 .bool_false,
823 => return .eq,947 => .eq,
824948
825 .bool_true => return .gt,949 .bool_true => .gt,
826950
827 .int_u64 => return std.math.order(lhs.cast(Payload.Int_u64).?.int, 0),951 .int_u64 => std.math.order(lhs.cast(Payload.Int_u64).?.int, 0),
828 .int_i64 => return std.math.order(lhs.cast(Payload.Int_i64).?.int, 0),952 .int_i64 => std.math.order(lhs.cast(Payload.Int_i64).?.int, 0),
829 .int_big_positive => return lhs.cast(Payload.IntBigPositive).?.asBigInt().orderAgainstScalar(0),953 .int_big_positive => lhs.cast(Payload.IntBigPositive).?.asBigInt().orderAgainstScalar(0),
830 .int_big_negative => return lhs.cast(Payload.IntBigNegative).?.asBigInt().orderAgainstScalar(0),954 .int_big_negative => lhs.cast(Payload.IntBigNegative).?.asBigInt().orderAgainstScalar(0),
831 }955
956 .float_16 => std.math.order(lhs.cast(Payload.Float_16).?.val, 0),
957 .float_32 => std.math.order(lhs.cast(Payload.Float_32).?.val, 0),
958 .float_64 => std.math.order(lhs.cast(Payload.Float_64).?.val, 0),
959 .float_128 => std.math.order(lhs.cast(Payload.Float_128).?.val, 0),
960 };
832 }961 }
833962
834 /// Asserts the value is comparable.963 /// Asserts the value is comparable.
835 pub fn order(lhs: Value, rhs: Value) std.math.Order {964 pub fn order(lhs: Value, rhs: Value) std.math.Order {
836 const lhs_tag = lhs.tag();965 const lhs_tag = lhs.tag();
837 const rhs_tag = lhs.tag();966 const rhs_tag = rhs.tag();
838 const lhs_is_zero = lhs_tag == .zero or lhs_tag == .the_one_possible_value;967 const lhs_is_zero = lhs_tag == .zero or lhs_tag == .the_one_possible_value;
839 const rhs_is_zero = rhs_tag == .zero or rhs_tag == .the_one_possible_value;968 const rhs_is_zero = rhs_tag == .zero or rhs_tag == .the_one_possible_value;
840 if (lhs_is_zero) return rhs.orderAgainstZero().invert();969 if (lhs_is_zero) return rhs.orderAgainstZero().invert();
841 if (rhs_is_zero) return lhs.orderAgainstZero();970 if (rhs_is_zero) return lhs.orderAgainstZero();
842971
843 // TODO floats972 const lhs_float = lhs.isFloat();
973 const rhs_float = rhs.isFloat();
974 if (lhs_float and rhs_float) {
975 if (lhs_tag == rhs_tag) {
976 return switch (lhs.tag()) {
977 .float_16 => return std.math.order(lhs.cast(Payload.Float_16).?.val, rhs.cast(Payload.Float_16).?.val),
978 .float_32 => return std.math.order(lhs.cast(Payload.Float_32).?.val, rhs.cast(Payload.Float_32).?.val),
979 .float_64 => return std.math.order(lhs.cast(Payload.Float_64).?.val, rhs.cast(Payload.Float_64).?.val),
980 .float_128 => return std.math.order(lhs.cast(Payload.Float_128).?.val, rhs.cast(Payload.Float_128).?.val),
981 else => unreachable,
982 };
983 }
984 }
985 if (lhs_float or rhs_float) {
986 const lhs_f128 = lhs.toFloat(f128);
987 const rhs_f128 = rhs.toFloat(f128);
988 return std.math.order(lhs_f128, rhs_f128);
989 }
844990
845 var lhs_bigint_space: BigIntSpace = undefined;991 var lhs_bigint_space: BigIntSpace = undefined;
846 var rhs_bigint_space: BigIntSpace = undefined;992 var rhs_bigint_space: BigIntSpace = undefined;
...@@ -864,19 +1010,12 @@ pub const Value = extern union {...@@ -864,19 +1010,12 @@ pub const Value = extern union {
864 return compare(a, .eq, b);1010 return compare(a, .eq, b);
865 }1011 }
8661012
867 pub fn toBool(self: Value) bool {
868 return switch (self.tag()) {
869 .bool_true => true,
870 .bool_false, .zero => false,
871 else => unreachable,
872 };
873 }
874
875 /// Asserts the value is a pointer and dereferences it.1013 /// Asserts the value is a pointer and dereferences it.
876 /// Returns error.AnalysisFail if the pointer points to a Decl that failed semantic analysis.1014 /// Returns error.AnalysisFail if the pointer points to a Decl that failed semantic analysis.
877 pub fn pointerDeref(self: Value, allocator: *Allocator) error{ AnalysisFail, OutOfMemory }!Value {1015 pub fn pointerDeref(self: Value, allocator: *Allocator) error{ AnalysisFail, OutOfMemory }!Value {
878 return switch (self.tag()) {1016 return switch (self.tag()) {
879 .ty,1017 .ty,
1018 .int_type,
880 .u8_type,1019 .u8_type,
881 .i8_type,1020 .i8_type,
882 .u16_type,1021 .u16_type,
...@@ -928,6 +1067,10 @@ pub const Value = extern union {...@@ -928,6 +1067,10 @@ pub const Value = extern union {
928 .bytes,1067 .bytes,
929 .undef,1068 .undef,
930 .repeated,1069 .repeated,
1070 .float_16,
1071 .float_32,
1072 .float_64,
1073 .float_128,
931 => unreachable,1074 => unreachable,
9321075
933 .the_one_possible_value => Value.initTag(.the_one_possible_value),1076 .the_one_possible_value => Value.initTag(.the_one_possible_value),
...@@ -946,6 +1089,7 @@ pub const Value = extern union {...@@ -946,6 +1089,7 @@ pub const Value = extern union {
946 pub fn elemValue(self: Value, allocator: *Allocator, index: usize) error{OutOfMemory}!Value {1089 pub fn elemValue(self: Value, allocator: *Allocator, index: usize) error{OutOfMemory}!Value {
947 switch (self.tag()) {1090 switch (self.tag()) {
948 .ty,1091 .ty,
1092 .int_type,
949 .u8_type,1093 .u8_type,
950 .i8_type,1094 .i8_type,
951 .u16_type,1095 .u16_type,
...@@ -999,6 +1143,10 @@ pub const Value = extern union {...@@ -999,6 +1143,10 @@ pub const Value = extern union {
999 .elem_ptr,1143 .elem_ptr,
1000 .ref_val,1144 .ref_val,
1001 .decl_ref,1145 .decl_ref,
1146 .float_16,
1147 .float_32,
1148 .float_64,
1149 .float_128,
1002 => unreachable,1150 => unreachable,
10031151
1004 .bytes => {1152 .bytes => {
...@@ -1032,6 +1180,7 @@ pub const Value = extern union {...@@ -1032,6 +1180,7 @@ pub const Value = extern union {
1032 pub fn isNull(self: Value) bool {1180 pub fn isNull(self: Value) bool {
1033 return switch (self.tag()) {1181 return switch (self.tag()) {
1034 .ty,1182 .ty,
1183 .int_type,
1035 .u8_type,1184 .u8_type,
1036 .i8_type,1185 .i8_type,
1037 .u16_type,1186 .u16_type,
...@@ -1085,6 +1234,10 @@ pub const Value = extern union {...@@ -1085,6 +1234,10 @@ pub const Value = extern union {
1085 .elem_ptr,1234 .elem_ptr,
1086 .bytes,1235 .bytes,
1087 .repeated,1236 .repeated,
1237 .float_16,
1238 .float_32,
1239 .float_64,
1240 .float_128,
1088 => false,1241 => false,
10891242
1090 .undef => unreachable,1243 .undef => unreachable,
...@@ -1092,6 +1245,20 @@ pub const Value = extern union {...@@ -1092,6 +1245,20 @@ pub const Value = extern union {
1092 };1245 };
1093 }1246 }
10941247
1248 /// Valid for all types. Asserts the value is not undefined.
1249 pub fn isFloat(self: Value) bool {
1250 return switch (self.tag()) {
1251 .undef => unreachable,
1252
1253 .float_16,
1254 .float_32,
1255 .float_64,
1256 .float_128,
1257 => true,
1258 else => false,
1259 };
1260 }
1261
1095 /// This type is not copyable since it may contain pointers to its inner data.1262 /// This type is not copyable since it may contain pointers to its inner data.
1096 pub const Payload = struct {1263 pub const Payload = struct {
1097 tag: Tag,1264 tag: Tag,
...@@ -1162,12 +1329,38 @@ pub const Value = extern union {...@@ -1162,12 +1329,38 @@ pub const Value = extern union {
1162 ty: Type,1329 ty: Type,
1163 };1330 };
11641331
1332 pub const IntType = struct {
1333 base: Payload = Payload{ .tag = .int_type },
1334 bits: u16,
1335 signed: bool,
1336 };
1337
1165 pub const Repeated = struct {1338 pub const Repeated = struct {
1166 base: Payload = Payload{ .tag = .ty },1339 base: Payload = Payload{ .tag = .ty },
1167 /// This value is repeated some number of times. The amount of times to repeat1340 /// This value is repeated some number of times. The amount of times to repeat
1168 /// is stored externally.1341 /// is stored externally.
1169 val: Value,1342 val: Value,
1170 };1343 };
1344
1345 pub const Float_16 = struct {
1346 base: Payload = .{ .tag = .float_16 },
1347 val: f16,
1348 };
1349
1350 pub const Float_32 = struct {
1351 base: Payload = .{ .tag = .float_32 },
1352 val: f32,
1353 };
1354
1355 pub const Float_64 = struct {
1356 base: Payload = .{ .tag = .float_64 },
1357 val: f64,
1358 };
1359
1360 pub const Float_128 = struct {
1361 base: Payload = .{ .tag = .float_128 },
1362 val: f128,
1363 };
1171 };1364 };
11721365
1173 /// Big enough to fit any non-BigInt value1366 /// Big enough to fit any non-BigInt value
src-self-hosted/zir.zig+43-17
...@@ -76,6 +76,7 @@ pub const Inst = struct {...@@ -76,6 +76,7 @@ pub const Inst = struct {
76 primitive,76 primitive,
77 intcast,77 intcast,
78 bitcast,78 bitcast,
79 floatcast,
79 elemptr,80 elemptr,
80 add,81 add,
81 sub,82 sub,
...@@ -137,6 +138,7 @@ pub const Inst = struct {...@@ -137,6 +138,7 @@ pub const Inst = struct {
137 .fntype => FnType,138 .fntype => FnType,
138 .intcast => IntCast,139 .intcast => IntCast,
139 .bitcast => BitCast,140 .bitcast => BitCast,
141 .floatcast => FloatCast,
140 .elemptr => ElemPtr,142 .elemptr => ElemPtr,
141 .condbr => CondBr,143 .condbr => CondBr,
142 };144 };
...@@ -169,6 +171,7 @@ pub const Inst = struct {...@@ -169,6 +171,7 @@ pub const Inst = struct {
169 .primitive,171 .primitive,
170 .intcast,172 .intcast,
171 .bitcast,173 .bitcast,
174 .floatcast,
172 .elemptr,175 .elemptr,
173 .add,176 .add,
174 .sub,177 .sub,
...@@ -556,19 +559,33 @@ pub const Inst = struct {...@@ -556,19 +559,33 @@ pub const Inst = struct {
556 };559 };
557 };560 };
558561
562 pub const FloatCast = struct {
563 pub const base_tag = Tag.floatcast;
564 pub const builtin_name = "@floatCast";
565 base: Inst,
566
567 positionals: struct {
568 dest_type: *Inst,
569 operand: *Inst,
570 },
571 kw_args: struct {},
572 };
573
559 pub const IntCast = struct {574 pub const IntCast = struct {
560 pub const base_tag = Tag.intcast;575 pub const base_tag = Tag.intcast;
576 pub const builtin_name = "@intCast";
561 base: Inst,577 base: Inst,
562578
563 positionals: struct {579 positionals: struct {
564 dest_type: *Inst,580 dest_type: *Inst,
565 value: *Inst,581 operand: *Inst,
566 },582 },
567 kw_args: struct {},583 kw_args: struct {},
568 };584 };
569585
570 pub const BitCast = struct {586 pub const BitCast = struct {
571 pub const base_tag = Tag.bitcast;587 pub const base_tag = Tag.bitcast;
588 pub const builtin_name = "@bitCast";
572 base: Inst,589 base: Inst,
573590
574 positionals: struct {591 positionals: struct {
...@@ -1618,6 +1635,28 @@ const EmitZIR = struct {...@@ -1618,6 +1635,28 @@ const EmitZIR = struct {
1618 return &new_inst.base;1635 return &new_inst.base;
1619 }1636 }
16201637
1638 fn emitCast(
1639 self: *EmitZIR,
1640 src: usize,
1641 new_body: ZirBody,
1642 old_inst: *ir.Inst.UnOp,
1643 comptime I: type,
1644 ) Allocator.Error!*Inst {
1645 const new_inst = try self.arena.allocator.create(I);
1646 new_inst.* = .{
1647 .base = .{
1648 .src = src,
1649 .tag = I.base_tag,
1650 },
1651 .positionals = .{
1652 .dest_type = (try self.emitType(src, old_inst.base.ty)).inst,
1653 .operand = try self.resolveInst(new_body, old_inst.operand),
1654 },
1655 .kw_args = .{},
1656 };
1657 return &new_inst.base;
1658 }
1659
1621 fn emitBody(1660 fn emitBody(
1622 self: *EmitZIR,1661 self: *EmitZIR,
1623 body: ir.Body,1662 body: ir.Body,
...@@ -1652,22 +1691,9 @@ const EmitZIR = struct {...@@ -1652,22 +1691,9 @@ const EmitZIR = struct {
1652 .cmp_gt => try self.emitBinOp(inst.src, new_body, inst.castTag(.cmp_gt).?, .cmp_gt),1691 .cmp_gt => try self.emitBinOp(inst.src, new_body, inst.castTag(.cmp_gt).?, .cmp_gt),
1653 .cmp_neq => try self.emitBinOp(inst.src, new_body, inst.castTag(.cmp_neq).?, .cmp_neq),1692 .cmp_neq => try self.emitBinOp(inst.src, new_body, inst.castTag(.cmp_neq).?, .cmp_neq),
16541693
1655 .bitcast => blk: {1694 .bitcast => try self.emitCast(inst.src, new_body, inst.castTag(.bitcast).?, Inst.BitCast),
1656 const old_inst = inst.castTag(.bitcast).?;1695 .intcast => try self.emitCast(inst.src, new_body, inst.castTag(.intcast).?, Inst.IntCast),
1657 const new_inst = try self.arena.allocator.create(Inst.BitCast);1696 .floatcast => try self.emitCast(inst.src, new_body, inst.castTag(.floatcast).?, Inst.FloatCast),
1658 new_inst.* = .{
1659 .base = .{
1660 .src = inst.src,
1661 .tag = Inst.BitCast.base_tag,
1662 },
1663 .positionals = .{
1664 .dest_type = (try self.emitType(inst.src, inst.ty)).inst,
1665 .operand = try self.resolveInst(new_body, old_inst.operand),
1666 },
1667 .kw_args = .{},
1668 };
1669 break :blk &new_inst.base;
1670 },
16711697
1672 .block => blk: {1698 .block => blk: {
1673 const old_inst = inst.castTag(.block).?;1699 const old_inst = inst.castTag(.block).?;
src/ir.cpp+3-2
...@@ -288,6 +288,7 @@ static IrInstGen *ir_analyze_struct_value_field_value(IrAnalyze *ira, IrInst* so...@@ -288,6 +288,7 @@ static IrInstGen *ir_analyze_struct_value_field_value(IrAnalyze *ira, IrInst* so
288static bool value_cmp_numeric_val_any(ZigValue *left, Cmp predicate, ZigValue *right);288static bool value_cmp_numeric_val_any(ZigValue *left, Cmp predicate, ZigValue *right);
289static bool value_cmp_numeric_val_all(ZigValue *left, Cmp predicate, ZigValue *right);289static bool value_cmp_numeric_val_all(ZigValue *left, Cmp predicate, ZigValue *right);
290static void memoize_field_init_val(CodeGen *codegen, ZigType *container_type, TypeStructField *field);290static void memoize_field_init_val(CodeGen *codegen, ZigType *container_type, TypeStructField *field);
291static void value_to_bigfloat(BigFloat *out, ZigValue *val);
291292
292#define ir_assert(OK, SOURCE_INSTRUCTION) ir_assert_impl((OK), (SOURCE_INSTRUCTION), __FILE__, __LINE__)293#define ir_assert(OK, SOURCE_INSTRUCTION) ir_assert_impl((OK), (SOURCE_INSTRUCTION), __FILE__, __LINE__)
293#define ir_assert_gen(OK, SOURCE_INSTRUCTION) ir_assert_gen_impl((OK), (SOURCE_INSTRUCTION), __FILE__, __LINE__)294#define ir_assert_gen(OK, SOURCE_INSTRUCTION) ir_assert_gen_impl((OK), (SOURCE_INSTRUCTION), __FILE__, __LINE__)
...@@ -10930,8 +10931,8 @@ static Cmp float_cmp(ZigValue *op1, ZigValue *op2) {...@@ -10930,8 +10931,8 @@ static Cmp float_cmp(ZigValue *op1, ZigValue *op2) {
10930 }10931 }
10931 BigFloat op1_big;10932 BigFloat op1_big;
10932 BigFloat op2_big;10933 BigFloat op2_big;
10933 float_init_bigfloat(op1, &op1_big);10934 value_to_bigfloat(&op1_big, op1);
10934 float_init_bigfloat(op2, &op2_big);10935 value_to_bigfloat(&op2_big, op2);
10935 return bigfloat_cmp(&op1_big, &op2_big);10936 return bigfloat_cmp(&op1_big, &op2_big);
10936}10937}
1093710938
test/stage1/behavior/floatop.zig+11
...@@ -434,6 +434,17 @@ fn testFloatComparisons() void {...@@ -434,6 +434,17 @@ fn testFloatComparisons() void {
434 }434 }
435}435}
436436
437test "different sized float comparisons" {
438 testDifferentSizedFloatComparisons();
439 comptime testDifferentSizedFloatComparisons();
440}
441
442fn testDifferentSizedFloatComparisons() void {
443 var a: f16 = 1;
444 var b: f64 = 2;
445 expect(a < b);
446}
447
437// TODO This is waiting on library support for the Windows build (not sure why the other's don't need it)448// TODO This is waiting on library support for the Windows build (not sure why the other's don't need it)
438//test "@nearbyint" {449//test "@nearbyint" {
439// comptime testNearbyInt();450// comptime testNearbyInt();