| author | |
| committer | |
| log | a92990f99312c946b5e527517a27a67a5a5513c0 |
| tree | 7362b21717b6a8cf27b2fbf4d04de74b4db7d00f |
| parent | 135580c1621513e7cfeed8098c087d1d6941fa97 |
5 files changed, 192 insertions(+), 36 deletions(-)
src-self-hosted/Module.zig+25-19| ... | @@ -1358,17 +1358,19 @@ fn astGenInfixOp(self: *Module, scope: *Scope, infix_node: *ast.Node.InfixOp) In | ... | @@ -1358,17 +1358,19 @@ fn astGenInfixOp(self: *Module, scope: *Scope, infix_node: *ast.Node.InfixOp) In |
| 1358 | const tree = scope.tree(); | 1358 | const tree = scope.tree(); |
| 1359 | const src = tree.token_locs[infix_node.op_token].start; | 1359 | const src = tree.token_locs[infix_node.op_token].start; |
| 1360 | 1360 | ||
| 1361 | const op: std.math.CompareOperator = switch (infix_node.op) { | ||
| 1362 | .BangEqual => .neq, | ||
| 1363 | .EqualEqual => .eq, | ||
| 1364 | .GreaterThan => .gt, | ||
| 1365 | .GreaterOrEqual => .gte, | ||
| 1366 | .LessThan => .lt, | ||
| 1367 | .LessOrEqual => .lte, | ||
| 1368 | else => unreachable, | ||
| 1369 | }; | ||
| 1370 | |||
| 1361 | return self.addZIRInst(scope, src, zir.Inst.Cmp, .{ | 1371 | return self.addZIRInst(scope, src, zir.Inst.Cmp, .{ |
| 1362 | .lhs = lhs, | 1372 | .lhs = lhs, |
| 1363 | .op = @as(std.math.CompareOperator, switch (infix_node.op) { | 1373 | .op = op, |
| 1364 | .BangEqual => .neq, | ||
| 1365 | .EqualEqual => .eq, | ||
| 1366 | .GreaterThan => .gt, | ||
| 1367 | .GreaterOrEqual => .gte, | ||
| 1368 | .LessThan => .lt, | ||
| 1369 | .LessOrEqual => .lte, | ||
| 1370 | else => unreachable, | ||
| 1371 | }), | ||
| 1372 | .rhs = rhs, | 1374 | .rhs = rhs, |
| 1373 | }, .{}); | 1375 | }, .{}); |
| 1374 | }, | 1376 | }, |
| ... | @@ -1415,11 +1417,13 @@ fn astGenIf(self: *Module, scope: *Scope, if_node: *ast.Node.If) InnerError!*zir | ... | @@ -1415,11 +1417,13 @@ fn astGenIf(self: *Module, scope: *Scope, if_node: *ast.Node.If) InnerError!*zir |
| 1415 | defer then_scope.instructions.deinit(self.gpa); | 1417 | defer then_scope.instructions.deinit(self.gpa); |
| 1416 | 1418 | ||
| 1417 | const then_result = try self.astGenExpr(&then_scope.base, if_node.body); | 1419 | const then_result = try self.astGenExpr(&then_scope.base, if_node.body); |
| 1418 | const then_src = tree.token_locs[if_node.body.lastToken()].start; | 1420 | if (!then_result.tag.isNoReturn()) { |
| 1419 | _ = try self.addZIRInst(&then_scope.base, then_src, zir.Inst.Break, .{ | 1421 | const then_src = tree.token_locs[if_node.body.lastToken()].start; |
| 1420 | .block = block, | 1422 | _ = try self.addZIRInst(&then_scope.base, then_src, zir.Inst.Break, .{ |
| 1421 | .operand = then_result, | 1423 | .block = block, |
| 1422 | }, .{}); | 1424 | .operand = then_result, |
| 1425 | }, .{}); | ||
| 1426 | } | ||
| 1423 | condbr.positionals.true_body = .{ | 1427 | condbr.positionals.true_body = .{ |
| 1424 | .instructions = try then_scope.arena.dupe(*zir.Inst, then_scope.instructions.items), | 1428 | .instructions = try then_scope.arena.dupe(*zir.Inst, then_scope.instructions.items), |
| 1425 | }; | 1429 | }; |
| ... | @@ -1433,11 +1437,13 @@ fn astGenIf(self: *Module, scope: *Scope, if_node: *ast.Node.If) InnerError!*zir | ... | @@ -1433,11 +1437,13 @@ fn astGenIf(self: *Module, scope: *Scope, if_node: *ast.Node.If) InnerError!*zir |
| 1433 | 1437 | ||
| 1434 | if (if_node.@"else") |else_node| { | 1438 | if (if_node.@"else") |else_node| { |
| 1435 | const else_result = try self.astGenExpr(&else_scope.base, else_node.body); | 1439 | const else_result = try self.astGenExpr(&else_scope.base, else_node.body); |
| 1436 | const else_src = tree.token_locs[else_node.body.lastToken()].start; | 1440 | if (!else_result.tag.isNoReturn()) { |
| 1437 | _ = try self.addZIRInst(&else_scope.base, else_src, zir.Inst.Break, .{ | 1441 | const else_src = tree.token_locs[else_node.body.lastToken()].start; |
| 1438 | .block = block, | 1442 | _ = try self.addZIRInst(&else_scope.base, else_src, zir.Inst.Break, .{ |
| 1439 | .operand = else_result, | 1443 | .block = block, |
| 1440 | }, .{}); | 1444 | .operand = else_result, |
| 1445 | }, .{}); | ||
| 1446 | } | ||
| 1441 | } else { | 1447 | } else { |
| 1442 | // TODO Optimization opportunity: we can avoid an allocation and a memcpy here | 1448 | // TODO Optimization opportunity: we can avoid an allocation and a memcpy here |
| 1443 | // by directly allocating the body for this one instruction. | 1449 | // by directly allocating the body for this one instruction. |
src-self-hosted/codegen.zig+70-4| ... | @@ -415,7 +415,46 @@ const Function = struct { | ... | @@ -415,7 +415,46 @@ const Function = struct { |
| 415 | // No side effects, so if it's unreferenced, do nothing. | 415 | // No side effects, so if it's unreferenced, do nothing. |
| 416 | if (inst.base.isUnused()) | 416 | if (inst.base.isUnused()) |
| 417 | return MCValue.dead; | 417 | return MCValue.dead; |
| 418 | const operand = try self.resolveInst(inst.args.operand); | ||
| 419 | switch (operand) { | ||
| 420 | .dead => unreachable, | ||
| 421 | .unreach => unreachable, | ||
| 422 | .compare_flags_unsigned => |op| return MCValue{ | ||
| 423 | .compare_flags_unsigned = switch (op) { | ||
| 424 | .gte => .lt, | ||
| 425 | .gt => .lte, | ||
| 426 | .neq => .eq, | ||
| 427 | .lt => .gte, | ||
| 428 | .lte => .gt, | ||
| 429 | .eq => .neq, | ||
| 430 | }, | ||
| 431 | }, | ||
| 432 | .compare_flags_signed => |op| return MCValue{ | ||
| 433 | .compare_flags_signed = switch (op) { | ||
| 434 | .gte => .lt, | ||
| 435 | .gt => .lte, | ||
| 436 | .neq => .eq, | ||
| 437 | .lt => .gte, | ||
| 438 | .lte => .gt, | ||
| 439 | .eq => .neq, | ||
| 440 | }, | ||
| 441 | }, | ||
| 442 | else => {}, | ||
| 443 | } | ||
| 444 | |||
| 418 | switch (arch) { | 445 | switch (arch) { |
| 446 | .x86_64 => { | ||
| 447 | var imm = ir.Inst.Constant{ | ||
| 448 | .base = .{ | ||
| 449 | .tag = .constant, | ||
| 450 | .deaths = 0, | ||
| 451 | .ty = inst.args.operand.ty, | ||
| 452 | .src = inst.args.operand.src, | ||
| 453 | }, | ||
| 454 | .val = Value.initTag(.bool_true), | ||
| 455 | }; | ||
| 456 | return try self.genX8664BinMath(&inst.base, inst.args.operand, &imm.base, 6, 0x30); | ||
| 457 | }, | ||
| 419 | else => return self.fail(inst.base.src, "TODO implement NOT for {}", .{self.target.cpu.arch}), | 458 | else => return self.fail(inst.base.src, "TODO implement NOT for {}", .{self.target.cpu.arch}), |
| 420 | } | 459 | } |
| 421 | } | 460 | } |
| ... | @@ -444,7 +483,7 @@ const Function = struct { | ... | @@ -444,7 +483,7 @@ const Function = struct { |
| 444 | } | 483 | } |
| 445 | } | 484 | } |
| 446 | 485 | ||
| 447 | /// ADD, SUB | 486 | /// ADD, SUB, XOR, OR, AND |
| 448 | fn genX8664BinMath(self: *Function, inst: *ir.Inst, op_lhs: *ir.Inst, op_rhs: *ir.Inst, opx: u8, mr: u8) !MCValue { | 487 | fn genX8664BinMath(self: *Function, inst: *ir.Inst, op_lhs: *ir.Inst, op_rhs: *ir.Inst, opx: u8, mr: u8) !MCValue { |
| 449 | try self.code.ensureCapacity(self.code.items.len + 8); | 488 | try self.code.ensureCapacity(self.code.items.len + 8); |
| 450 | 489 | ||
| ... | @@ -705,7 +744,7 @@ const Function = struct { | ... | @@ -705,7 +744,7 @@ const Function = struct { |
| 705 | 744 | ||
| 706 | fn genCondBr(self: *Function, inst: *ir.Inst.CondBr, comptime arch: std.Target.Cpu.Arch) !MCValue { | 745 | fn genCondBr(self: *Function, inst: *ir.Inst.CondBr, comptime arch: std.Target.Cpu.Arch) !MCValue { |
| 707 | switch (arch) { | 746 | switch (arch) { |
| 708 | .i386, .x86_64 => { | 747 | .x86_64 => { |
| 709 | try self.code.ensureCapacity(self.code.items.len + 6); | 748 | try self.code.ensureCapacity(self.code.items.len + 6); |
| 710 | 749 | ||
| 711 | const cond = try self.resolveInst(inst.args.condition); | 750 | const cond = try self.resolveInst(inst.args.condition); |
| ... | @@ -734,7 +773,20 @@ const Function = struct { | ... | @@ -734,7 +773,20 @@ const Function = struct { |
| 734 | }; | 773 | }; |
| 735 | return self.genX86CondBr(inst, opcode, arch); | 774 | return self.genX86CondBr(inst, opcode, arch); |
| 736 | }, | 775 | }, |
| 737 | else => return self.fail(inst.base.src, "TODO implement condbr {} when condition not already in the compare flags", .{self.target.cpu.arch}), | 776 | .register => |reg_usize| { |
| 777 | const reg = @intToEnum(Reg(arch), @intCast(u8, reg_usize)); | ||
| 778 | // test reg, 1 | ||
| 779 | // TODO detect al, ax, eax | ||
| 780 | try self.code.ensureCapacity(self.code.items.len + 4); | ||
| 781 | self.rex(.{ .b = reg.isExtended(), .w = reg.size() == 64 }); | ||
| 782 | self.code.appendSliceAssumeCapacity(&[_]u8{ | ||
| 783 | 0xf6, | ||
| 784 | @as(u8, 0xC0) | (0 << 3) | @truncate(u3, reg.id()), | ||
| 785 | 0x01, | ||
| 786 | }); | ||
| 787 | return self.genX86CondBr(inst, 0x84, arch); | ||
| 788 | }, | ||
| 789 | else => return self.fail(inst.base.src, "TODO implement condbr {} when condition is {}", .{ self.target.cpu.arch, @tagName(cond) }), | ||
| 738 | } | 790 | } |
| 739 | }, | 791 | }, |
| 740 | else => return self.fail(inst.base.src, "TODO implement condbr for {}", .{self.target.cpu.arch}), | 792 | else => return self.fail(inst.base.src, "TODO implement condbr for {}", .{self.target.cpu.arch}), |
| ... | @@ -892,7 +944,18 @@ const Function = struct { | ... | @@ -892,7 +944,18 @@ const Function = struct { |
| 892 | .none => unreachable, | 944 | .none => unreachable, |
| 893 | .unreach => unreachable, | 945 | .unreach => unreachable, |
| 894 | .compare_flags_unsigned => |op| { | 946 | .compare_flags_unsigned => |op| { |
| 895 | return self.fail(src, "TODO set register with compare flags value (unsigned)", .{}); | 947 | try self.code.ensureCapacity(self.code.items.len + 3); |
| 948 | self.rex(.{ .b = reg.isExtended(), .w = reg.size() == 64 }); | ||
| 949 | const opcode: u8 = switch (op) { | ||
| 950 | .gte => 0x93, | ||
| 951 | .gt => 0x97, | ||
| 952 | .neq => 0x95, | ||
| 953 | .lt => 0x92, | ||
| 954 | .lte => 0x96, | ||
| 955 | .eq => 0x94, | ||
| 956 | }; | ||
| 957 | const id = @as(u8, reg.id() & 0b111); | ||
| 958 | self.code.appendSliceAssumeCapacity(&[_]u8{ 0x0f, opcode, 0xC0 | id }); | ||
| 896 | }, | 959 | }, |
| 897 | .compare_flags_signed => |op| { | 960 | .compare_flags_signed => |op| { |
| 898 | return self.fail(src, "TODO set register with compare flags value (signed)", .{}); | 961 | return self.fail(src, "TODO set register with compare flags value (signed)", .{}); |
| ... | @@ -1147,6 +1210,9 @@ const Function = struct { | ... | @@ -1147,6 +1210,9 @@ const Function = struct { |
| 1147 | } | 1210 | } |
| 1148 | return MCValue{ .immediate = typed_value.val.toUnsignedInt() }; | 1211 | return MCValue{ .immediate = typed_value.val.toUnsignedInt() }; |
| 1149 | }, | 1212 | }, |
| 1213 | .Bool => { | ||
| 1214 | return MCValue{ .immediate = @boolToInt(typed_value.val.toBool()) }; | ||
| 1215 | }, | ||
| 1150 | .ComptimeInt => unreachable, // semantic analysis prevents this | 1216 | .ComptimeInt => unreachable, // semantic analysis prevents this |
| 1151 | .ComptimeFloat => unreachable, // semantic analysis prevents this | 1217 | .ComptimeFloat => unreachable, // semantic analysis prevents this |
| 1152 | else => return self.fail(src, "TODO implement const of type '{}'", .{typed_value.ty}), | 1218 | else => return self.fail(src, "TODO implement const of type '{}'", .{typed_value.ty}), |
src-self-hosted/type.zig+17-2| ... | @@ -163,6 +163,22 @@ pub const Type = extern union { | ... | @@ -163,6 +163,22 @@ pub const Type = extern union { |
| 163 | return sentinel_b == null; | 163 | return sentinel_b == null; |
| 164 | } | 164 | } |
| 165 | }, | 165 | }, |
| 166 | .Fn => { | ||
| 167 | if (!a.fnReturnType().eql(b.fnReturnType())) | ||
| 168 | return false; | ||
| 169 | if (a.fnCallingConvention() != b.fnCallingConvention()) | ||
| 170 | return false; | ||
| 171 | const a_param_len = a.fnParamLen(); | ||
| 172 | const b_param_len = b.fnParamLen(); | ||
| 173 | if (a_param_len != b_param_len) | ||
| 174 | return false; | ||
| 175 | var i: usize = 0; | ||
| 176 | while (i < a_param_len) : (i += 1) { | ||
| 177 | if (!a.fnParamType(i).eql(b.fnParamType(i))) | ||
| 178 | return false; | ||
| 179 | } | ||
| 180 | return true; | ||
| 181 | }, | ||
| 166 | .Float, | 182 | .Float, |
| 167 | .Struct, | 183 | .Struct, |
| 168 | .Optional, | 184 | .Optional, |
| ... | @@ -170,14 +186,13 @@ pub const Type = extern union { | ... | @@ -170,14 +186,13 @@ pub const Type = extern union { |
| 170 | .ErrorSet, | 186 | .ErrorSet, |
| 171 | .Enum, | 187 | .Enum, |
| 172 | .Union, | 188 | .Union, |
| 173 | .Fn, | ||
| 174 | .BoundFn, | 189 | .BoundFn, |
| 175 | .Opaque, | 190 | .Opaque, |
| 176 | .Frame, | 191 | .Frame, |
| 177 | .AnyFrame, | 192 | .AnyFrame, |
| 178 | .Vector, | 193 | .Vector, |
| 179 | .EnumLiteral, | 194 | .EnumLiteral, |
| 180 | => @panic("TODO implement more Type equality comparison"), | 195 | => std.debug.panic("TODO implement Type equality comparison of {} and {}", .{ a, b }), |
| 181 | } | 196 | } |
| 182 | } | 197 | } |
| 183 | 198 |
src-self-hosted/value.zig+23-11| ... | @@ -427,8 +427,6 @@ pub const Value = extern union { | ... | @@ -427,8 +427,6 @@ pub const Value = extern union { |
| 427 | .fn_ccc_void_no_args_type, | 427 | .fn_ccc_void_no_args_type, |
| 428 | .single_const_pointer_to_comptime_int_type, | 428 | .single_const_pointer_to_comptime_int_type, |
| 429 | .const_slice_u8_type, | 429 | .const_slice_u8_type, |
| 430 | .bool_true, | ||
| 431 | .bool_false, | ||
| 432 | .null_value, | 430 | .null_value, |
| 433 | .function, | 431 | .function, |
| 434 | .ref_val, | 432 | .ref_val, |
| ... | @@ -441,8 +439,11 @@ pub const Value = extern union { | ... | @@ -441,8 +439,11 @@ pub const Value = extern union { |
| 441 | 439 | ||
| 442 | .the_one_possible_value, // An integer with one possible value is always zero. | 440 | .the_one_possible_value, // An integer with one possible value is always zero. |
| 443 | .zero, | 441 | .zero, |
| 442 | .bool_false, | ||
| 444 | => return BigIntMutable.init(&space.limbs, 0).toConst(), | 443 | => return BigIntMutable.init(&space.limbs, 0).toConst(), |
| 445 | 444 | ||
| 445 | .bool_true => return BigIntMutable.init(&space.limbs, 1).toConst(), | ||
| 446 | |||
| 446 | .int_u64 => return BigIntMutable.init(&space.limbs, self.cast(Payload.Int_u64).?.int).toConst(), | 447 | .int_u64 => return BigIntMutable.init(&space.limbs, self.cast(Payload.Int_u64).?.int).toConst(), |
| 447 | .int_i64 => return BigIntMutable.init(&space.limbs, self.cast(Payload.Int_i64).?.int).toConst(), | 448 | .int_i64 => return BigIntMutable.init(&space.limbs, self.cast(Payload.Int_i64).?.int).toConst(), |
| 448 | .int_big_positive => return self.cast(Payload.IntBigPositive).?.asBigInt(), | 449 | .int_big_positive => return self.cast(Payload.IntBigPositive).?.asBigInt(), |
| ... | @@ -493,8 +494,6 @@ pub const Value = extern union { | ... | @@ -493,8 +494,6 @@ pub const Value = extern union { |
| 493 | .fn_ccc_void_no_args_type, | 494 | .fn_ccc_void_no_args_type, |
| 494 | .single_const_pointer_to_comptime_int_type, | 495 | .single_const_pointer_to_comptime_int_type, |
| 495 | .const_slice_u8_type, | 496 | .const_slice_u8_type, |
| 496 | .bool_true, | ||
| 497 | .bool_false, | ||
| 498 | .null_value, | 497 | .null_value, |
| 499 | .function, | 498 | .function, |
| 500 | .ref_val, | 499 | .ref_val, |
| ... | @@ -507,8 +506,11 @@ pub const Value = extern union { | ... | @@ -507,8 +506,11 @@ pub const Value = extern union { |
| 507 | 506 | ||
| 508 | .zero, | 507 | .zero, |
| 509 | .the_one_possible_value, // an integer with one possible value is always zero | 508 | .the_one_possible_value, // an integer with one possible value is always zero |
| 509 | .bool_false, | ||
| 510 | => return 0, | 510 | => return 0, |
| 511 | 511 | ||
| 512 | .bool_true => return 1, | ||
| 513 | |||
| 512 | .int_u64 => return self.cast(Payload.Int_u64).?.int, | 514 | .int_u64 => return self.cast(Payload.Int_u64).?.int, |
| 513 | .int_i64 => return @intCast(u64, self.cast(Payload.Int_u64).?.int), | 515 | .int_i64 => return @intCast(u64, self.cast(Payload.Int_u64).?.int), |
| 514 | .int_big_positive => return self.cast(Payload.IntBigPositive).?.asBigInt().to(u64) catch unreachable, | 516 | .int_big_positive => return self.cast(Payload.IntBigPositive).?.asBigInt().to(u64) catch unreachable, |
| ... | @@ -560,8 +562,6 @@ pub const Value = extern union { | ... | @@ -560,8 +562,6 @@ pub const Value = extern union { |
| 560 | .fn_ccc_void_no_args_type, | 562 | .fn_ccc_void_no_args_type, |
| 561 | .single_const_pointer_to_comptime_int_type, | 563 | .single_const_pointer_to_comptime_int_type, |
| 562 | .const_slice_u8_type, | 564 | .const_slice_u8_type, |
| 563 | .bool_true, | ||
| 564 | .bool_false, | ||
| 565 | .null_value, | 565 | .null_value, |
| 566 | .function, | 566 | .function, |
| 567 | .ref_val, | 567 | .ref_val, |
| ... | @@ -574,8 +574,11 @@ pub const Value = extern union { | ... | @@ -574,8 +574,11 @@ pub const Value = extern union { |
| 574 | 574 | ||
| 575 | .the_one_possible_value, // an integer with one possible value is always zero | 575 | .the_one_possible_value, // an integer with one possible value is always zero |
| 576 | .zero, | 576 | .zero, |
| 577 | .bool_false, | ||
| 577 | => return 0, | 578 | => return 0, |
| 578 | 579 | ||
| 580 | .bool_true => return 1, | ||
| 581 | |||
| 579 | .int_u64 => { | 582 | .int_u64 => { |
| 580 | const x = self.cast(Payload.Int_u64).?.int; | 583 | const x = self.cast(Payload.Int_u64).?.int; |
| 581 | if (x == 0) return 0; | 584 | if (x == 0) return 0; |
| ... | @@ -632,8 +635,6 @@ pub const Value = extern union { | ... | @@ -632,8 +635,6 @@ pub const Value = extern union { |
| 632 | .fn_ccc_void_no_args_type, | 635 | .fn_ccc_void_no_args_type, |
| 633 | .single_const_pointer_to_comptime_int_type, | 636 | .single_const_pointer_to_comptime_int_type, |
| 634 | .const_slice_u8_type, | 637 | .const_slice_u8_type, |
| 635 | .bool_true, | ||
| 636 | .bool_false, | ||
| 637 | .null_value, | 638 | .null_value, |
| 638 | .function, | 639 | .function, |
| 639 | .ref_val, | 640 | .ref_val, |
| ... | @@ -646,8 +647,18 @@ pub const Value = extern union { | ... | @@ -646,8 +647,18 @@ pub const Value = extern union { |
| 646 | .zero, | 647 | .zero, |
| 647 | .undef, | 648 | .undef, |
| 648 | .the_one_possible_value, // an integer with one possible value is always zero | 649 | .the_one_possible_value, // an integer with one possible value is always zero |
| 650 | .bool_false, | ||
| 649 | => return true, | 651 | => return true, |
| 650 | 652 | ||
| 653 | .bool_true => { | ||
| 654 | const info = ty.intInfo(target); | ||
| 655 | if (info.signed) { | ||
| 656 | return info.bits >= 2; | ||
| 657 | } else { | ||
| 658 | return info.bits >= 1; | ||
| 659 | } | ||
| 660 | }, | ||
| 661 | |||
| 651 | .int_u64 => switch (ty.zigTypeTag()) { | 662 | .int_u64 => switch (ty.zigTypeTag()) { |
| 652 | .Int => { | 663 | .Int => { |
| 653 | const x = self.cast(Payload.Int_u64).?.int; | 664 | const x = self.cast(Payload.Int_u64).?.int; |
| ... | @@ -796,8 +807,6 @@ pub const Value = extern union { | ... | @@ -796,8 +807,6 @@ pub const Value = extern union { |
| 796 | .fn_ccc_void_no_args_type, | 807 | .fn_ccc_void_no_args_type, |
| 797 | .single_const_pointer_to_comptime_int_type, | 808 | .single_const_pointer_to_comptime_int_type, |
| 798 | .const_slice_u8_type, | 809 | .const_slice_u8_type, |
| 799 | .bool_true, | ||
| 800 | .bool_false, | ||
| 801 | .null_value, | 810 | .null_value, |
| 802 | .function, | 811 | .function, |
| 803 | .ref_val, | 812 | .ref_val, |
| ... | @@ -810,8 +819,11 @@ pub const Value = extern union { | ... | @@ -810,8 +819,11 @@ pub const Value = extern union { |
| 810 | 819 | ||
| 811 | .zero, | 820 | .zero, |
| 812 | .the_one_possible_value, // an integer with one possible value is always zero | 821 | .the_one_possible_value, // an integer with one possible value is always zero |
| 822 | .bool_false, | ||
| 813 | => return .eq, | 823 | => return .eq, |
| 814 | 824 | ||
| 825 | .bool_true => return .gt, | ||
| 826 | |||
| 815 | .int_u64 => return std.math.order(lhs.cast(Payload.Int_u64).?.int, 0), | 827 | .int_u64 => return std.math.order(lhs.cast(Payload.Int_u64).?.int, 0), |
| 816 | .int_i64 => return std.math.order(lhs.cast(Payload.Int_i64).?.int, 0), | 828 | .int_i64 => return std.math.order(lhs.cast(Payload.Int_i64).?.int, 0), |
| 817 | .int_big_positive => return lhs.cast(Payload.IntBigPositive).?.asBigInt().orderAgainstScalar(0), | 829 | .int_big_positive => return lhs.cast(Payload.IntBigPositive).?.asBigInt().orderAgainstScalar(0), |
| ... | @@ -855,7 +867,7 @@ pub const Value = extern union { | ... | @@ -855,7 +867,7 @@ pub const Value = extern union { |
| 855 | pub fn toBool(self: Value) bool { | 867 | pub fn toBool(self: Value) bool { |
| 856 | return switch (self.tag()) { | 868 | return switch (self.tag()) { |
| 857 | .bool_true => true, | 869 | .bool_true => true, |
| 858 | .bool_false => false, | 870 | .bool_false, .zero => false, |
| 859 | else => unreachable, | 871 | else => unreachable, |
| 860 | }; | 872 | }; |
| 861 | } | 873 | } |
test/stage2/compare_output.zig+57| ... | @@ -170,4 +170,61 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -170,4 +170,61 @@ pub fn addCases(ctx: *TestContext) !void { |
| 170 | "", | 170 | "", |
| 171 | ); | 171 | ); |
| 172 | } | 172 | } |
| 173 | { | ||
| 174 | var case = ctx.exe("assert function", linux_x64); | ||
| 175 | case.addCompareOutput( | ||
| 176 | \\export fn _start() noreturn { | ||
| 177 | \\ add(3, 4); | ||
| 178 | \\ | ||
| 179 | \\ exit(); | ||
| 180 | \\} | ||
| 181 | \\ | ||
| 182 | \\fn add(a: u32, b: u32) void { | ||
| 183 | \\ assert(a + b == 7); | ||
| 184 | \\} | ||
| 185 | \\ | ||
| 186 | \\pub fn assert(ok: bool) void { | ||
| 187 | \\ if (!ok) unreachable; // assertion failure | ||
| 188 | \\} | ||
| 189 | \\ | ||
| 190 | \\fn exit() noreturn { | ||
| 191 | \\ asm volatile ("syscall" | ||
| 192 | \\ : | ||
| 193 | \\ : [number] "{rax}" (231), | ||
| 194 | \\ [arg1] "{rdi}" (0) | ||
| 195 | \\ : "rcx", "r11", "memory" | ||
| 196 | \\ ); | ||
| 197 | \\ unreachable; | ||
| 198 | \\} | ||
| 199 | , | ||
| 200 | "", | ||
| 201 | ); | ||
| 202 | case.addCompareOutput( | ||
| 203 | \\export fn _start() noreturn { | ||
| 204 | \\ add(100, 200); | ||
| 205 | \\ | ||
| 206 | \\ exit(); | ||
| 207 | \\} | ||
| 208 | \\ | ||
| 209 | \\fn add(a: u32, b: u32) void { | ||
| 210 | \\ assert(a + b == 300); | ||
| 211 | \\} | ||
| 212 | \\ | ||
| 213 | \\pub fn assert(ok: bool) void { | ||
| 214 | \\ if (!ok) unreachable; // assertion failure | ||
| 215 | \\} | ||
| 216 | \\ | ||
| 217 | \\fn exit() noreturn { | ||
| 218 | \\ asm volatile ("syscall" | ||
| 219 | \\ : | ||
| 220 | \\ : [number] "{rax}" (231), | ||
| 221 | \\ [arg1] "{rdi}" (0) | ||
| 222 | \\ : "rcx", "r11", "memory" | ||
| 223 | \\ ); | ||
| 224 | \\ unreachable; | ||
| 225 | \\} | ||
| 226 | , | ||
| 227 | "", | ||
| 228 | ); | ||
| 229 | } | ||
| 173 | } | 230 | } |