| author | |
| committer | |
| log | cc26cb9b2366723a8149e9f79e8252936cb69b73 |
| tree | 30e2bcaa34d25f747f5ecb5ae193919b26818bee |
| parent | fb28349349483c5e1c9523b19c2158cb465cf4e9 |
4 files changed, 95 insertions(+), 10 deletions(-)
src-self-hosted/astgen.zig+7-5| ... | @@ -802,7 +802,7 @@ fn catchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Catch) | ... | @@ -802,7 +802,7 @@ fn catchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Catch) |
| 802 | const err_name = tree.tokenSlice(payload.castTag(.Payload).?.error_symbol.firstToken()); | 802 | const err_name = tree.tokenSlice(payload.castTag(.Payload).?.error_symbol.firstToken()); |
| 803 | if (mem.eql(u8, err_name, "_")) | 803 | if (mem.eql(u8, err_name, "_")) |
| 804 | break :blk &err_scope.base; | 804 | break :blk &err_scope.base; |
| 805 | 805 | ||
| 806 | const unwrapped_err_ptr = try addZIRUnOp(mod, &err_scope.base, src, .unwrap_err_code, err_union_ptr); | 806 | const unwrapped_err_ptr = try addZIRUnOp(mod, &err_scope.base, src, .unwrap_err_code, err_union_ptr); |
| 807 | err_val_scope = .{ | 807 | err_val_scope = .{ |
| 808 | .parent = &err_scope.base, | 808 | .parent = &err_scope.base, |
| ... | @@ -1374,7 +1374,8 @@ fn forExpr(mod: *Module, scope: *Scope, rl: ResultLoc, for_node: *ast.Node.For) | ... | @@ -1374,7 +1374,8 @@ fn forExpr(mod: *Module, scope: *Scope, rl: ResultLoc, for_node: *ast.Node.For) |
| 1374 | .ty = Type.initTag(.usize), | 1374 | .ty = Type.initTag(.usize), |
| 1375 | .val = Value.initTag(.one), | 1375 | .val = Value.initTag(.one), |
| 1376 | }); | 1376 | }); |
| 1377 | const index_plus_one = try addZIRBinOp(mod, &loop_scope.base, for_src, .add, index, one); | 1377 | const index_2 = try addZIRUnOp(mod, &loop_scope.base, cond_src, .deref, index_ptr); |
| 1378 | const index_plus_one = try addZIRBinOp(mod, &loop_scope.base, for_src, .add, index_2, one); | ||
| 1378 | _ = try addZIRBinOp(mod, &loop_scope.base, for_src, .store, index_ptr, index_plus_one); | 1379 | _ = try addZIRBinOp(mod, &loop_scope.base, for_src, .store, index_ptr, index_plus_one); |
| 1379 | 1380 | ||
| 1380 | // looping stuff | 1381 | // looping stuff |
| ... | @@ -1382,7 +1383,7 @@ fn forExpr(mod: *Module, scope: *Scope, rl: ResultLoc, for_node: *ast.Node.For) | ... | @@ -1382,7 +1383,7 @@ fn forExpr(mod: *Module, scope: *Scope, rl: ResultLoc, for_node: *ast.Node.For) |
| 1382 | .instructions = try for_scope.arena.dupe(*zir.Inst, loop_scope.instructions.items), | 1383 | .instructions = try for_scope.arena.dupe(*zir.Inst, loop_scope.instructions.items), |
| 1383 | }); | 1384 | }); |
| 1384 | const for_block = try addZIRInstBlock(mod, scope, for_src, .{ | 1385 | const for_block = try addZIRInstBlock(mod, scope, for_src, .{ |
| 1385 | .instructions = try scope.arena().dupe(*zir.Inst, for_scope.instructions.items), | 1386 | .instructions = try for_scope.arena.dupe(*zir.Inst, for_scope.instructions.items), |
| 1386 | }); | 1387 | }); |
| 1387 | 1388 | ||
| 1388 | // while body | 1389 | // while body |
| ... | @@ -1404,7 +1405,7 @@ fn forExpr(mod: *Module, scope: *Scope, rl: ResultLoc, for_node: *ast.Node.For) | ... | @@ -1404,7 +1405,7 @@ fn forExpr(mod: *Module, scope: *Scope, rl: ResultLoc, for_node: *ast.Node.For) |
| 1404 | .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = for_block }, | 1405 | .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = for_block }, |
| 1405 | }; | 1406 | }; |
| 1406 | 1407 | ||
| 1407 | var index_scope: Scope.LocalVal = undefined; | 1408 | var index_scope: Scope.LocalPtr = undefined; |
| 1408 | const then_sub_scope = blk: { | 1409 | const then_sub_scope = blk: { |
| 1409 | const payload = for_node.payload.castTag(.PointerIndexPayload).?; | 1410 | const payload = for_node.payload.castTag(.PointerIndexPayload).?; |
| 1410 | const is_ptr = payload.ptr_token != null; | 1411 | const is_ptr = payload.ptr_token != null; |
| ... | @@ -1422,11 +1423,12 @@ fn forExpr(mod: *Module, scope: *Scope, rl: ResultLoc, for_node: *ast.Node.For) | ... | @@ -1422,11 +1423,12 @@ fn forExpr(mod: *Module, scope: *Scope, rl: ResultLoc, for_node: *ast.Node.For) |
| 1422 | if (mem.eql(u8, index_name, "_")) { | 1423 | if (mem.eql(u8, index_name, "_")) { |
| 1423 | break :blk &then_scope.base; | 1424 | break :blk &then_scope.base; |
| 1424 | } | 1425 | } |
| 1426 | // TODO make this const without an extra copy? | ||
| 1425 | index_scope = .{ | 1427 | index_scope = .{ |
| 1426 | .parent = &then_scope.base, | 1428 | .parent = &then_scope.base, |
| 1427 | .gen_zir = &then_scope, | 1429 | .gen_zir = &then_scope, |
| 1428 | .name = index_name, | 1430 | .name = index_name, |
| 1429 | .inst = index, | 1431 | .ptr = index_ptr, |
| 1430 | }; | 1432 | }; |
| 1431 | break :blk &index_scope.base; | 1433 | break :blk &index_scope.base; |
| 1432 | }; | 1434 | }; |
src-self-hosted/codegen.zig+28-4| ... | @@ -829,6 +829,16 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -829,6 +829,16 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 829 | // No side effects, so if it's unreferenced, do nothing. | 829 | // No side effects, so if it's unreferenced, do nothing. |
| 830 | if (inst.base.isUnused()) | 830 | if (inst.base.isUnused()) |
| 831 | return MCValue.dead; | 831 | return MCValue.dead; |
| 832 | |||
| 833 | const operand = try self.resolveInst(inst.operand); | ||
| 834 | const info_a = inst.operand.ty.intInfo(self.target.*); | ||
| 835 | const info_b = inst.base.ty.intInfo(self.target.*); | ||
| 836 | if (info_a.signed != info_b.signed) | ||
| 837 | return self.fail(inst.base.src, "TODO gen intcast sign safety in semantic analysis", .{}); | ||
| 838 | |||
| 839 | if (info_a.bits == info_b.bits) | ||
| 840 | return operand; | ||
| 841 | |||
| 832 | switch (arch) { | 842 | switch (arch) { |
| 833 | else => return self.fail(inst.base.src, "TODO implement intCast for {}", .{self.target.cpu.arch}), | 843 | else => return self.fail(inst.base.src, "TODO implement intCast for {}", .{self.target.cpu.arch}), |
| 834 | } | 844 | } |
| ... | @@ -2039,15 +2049,29 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -2039,15 +2049,29 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 2039 | mem.writeIntLittle(u32, self.code.addManyAsArrayAssumeCapacity(4), x); | 2049 | mem.writeIntLittle(u32, self.code.addManyAsArrayAssumeCapacity(4), x); |
| 2040 | }, | 2050 | }, |
| 2041 | 8 => { | 2051 | 8 => { |
| 2042 | return self.fail(src, "TODO implement set abi_size=8 stack variable with immediate", .{}); | 2052 | // We have a positive stack offset value but we want a twos complement negative |
| 2053 | // offset from rbp, which is at the top of the stack frame. | ||
| 2054 | const negative_offset = @intCast(i8, -@intCast(i32, adj_off)); | ||
| 2055 | const twos_comp = @bitCast(u8, negative_offset); | ||
| 2056 | |||
| 2057 | // 64 bit write to memory would take two mov's anyways so we | ||
| 2058 | // insted just use two 32 bit writes to avoid register allocation | ||
| 2059 | try self.code.ensureCapacity(self.code.items.len + 14); | ||
| 2060 | var buf: [8]u8 = undefined; | ||
| 2061 | mem.writeIntLittle(u64, &buf, x_big); | ||
| 2062 | |||
| 2063 | // mov DWORD PTR [rbp+offset+4], immediate | ||
| 2064 | self.code.appendSliceAssumeCapacity(&[_]u8{ 0xc7, 0x45, twos_comp + 4}); | ||
| 2065 | self.code.appendSliceAssumeCapacity(buf[4..8]); | ||
| 2066 | |||
| 2067 | // mov DWORD PTR [rbp+offset], immediate | ||
| 2068 | self.code.appendSliceAssumeCapacity(&[_]u8{ 0xc7, 0x45, twos_comp }); | ||
| 2069 | self.code.appendSliceAssumeCapacity(buf[0..4]); | ||
| 2043 | }, | 2070 | }, |
| 2044 | else => { | 2071 | else => { |
| 2045 | return self.fail(src, "TODO implement set abi_size=large stack variable with immediate", .{}); | 2072 | return self.fail(src, "TODO implement set abi_size=large stack variable with immediate", .{}); |
| 2046 | }, | 2073 | }, |
| 2047 | } | 2074 | } |
| 2048 | if (x_big <= math.maxInt(u32)) {} else { | ||
| 2049 | return self.fail(src, "TODO implement set stack variable with large immediate", .{}); | ||
| 2050 | } | ||
| 2051 | }, | 2075 | }, |
| 2052 | .embedded_in_code => |code_offset| { | 2076 | .embedded_in_code => |code_offset| { |
| 2053 | return self.fail(src, "TODO implement set stack variable from embedded_in_code", .{}); | 2077 | return self.fail(src, "TODO implement set stack variable from embedded_in_code", .{}); |
src-self-hosted/zir_sema.zig+1-1| ... | @@ -112,7 +112,7 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError! | ... | @@ -112,7 +112,7 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError! |
| 112 | .condbr => return analyzeInstCondBr(mod, scope, old_inst.castTag(.condbr).?), | 112 | .condbr => return analyzeInstCondBr(mod, scope, old_inst.castTag(.condbr).?), |
| 113 | .isnull => return analyzeInstIsNonNull(mod, scope, old_inst.castTag(.isnull).?, true), | 113 | .isnull => return analyzeInstIsNonNull(mod, scope, old_inst.castTag(.isnull).?, true), |
| 114 | .isnonnull => return analyzeInstIsNonNull(mod, scope, old_inst.castTag(.isnonnull).?, false), | 114 | .isnonnull => return analyzeInstIsNonNull(mod, scope, old_inst.castTag(.isnonnull).?, false), |
| 115 | .iserr => return analyzeInstIsErr(mod, scope, old_inst.castTag(.iserr).?, true), | 115 | .iserr => return analyzeInstIsErr(mod, scope, old_inst.castTag(.iserr).?), |
| 116 | .boolnot => return analyzeInstBoolNot(mod, scope, old_inst.castTag(.boolnot).?), | 116 | .boolnot => return analyzeInstBoolNot(mod, scope, old_inst.castTag(.boolnot).?), |
| 117 | .typeof => return analyzeInstTypeOf(mod, scope, old_inst.castTag(.typeof).?), | 117 | .typeof => return analyzeInstTypeOf(mod, scope, old_inst.castTag(.typeof).?), |
| 118 | .optional_type => return analyzeInstOptionalType(mod, scope, old_inst.castTag(.optional_type).?), | 118 | .optional_type => return analyzeInstOptionalType(mod, scope, old_inst.castTag(.optional_type).?), |
test/stage2/test.zig+59| ... | @@ -845,6 +845,65 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -845,6 +845,65 @@ pub fn addCases(ctx: *TestContext) !void { |
| 845 | , | 845 | , |
| 846 | "", | 846 | "", |
| 847 | ); | 847 | ); |
| 848 | |||
| 849 | // 64bit set stack | ||
| 850 | case.addCompareOutput( | ||
| 851 | \\export fn _start() noreturn { | ||
| 852 | \\ var i: u64 = 0xFFEEDDCCBBAA9988; | ||
| 853 | \\ assert(i == 0xFFEEDDCCBBAA9988); | ||
| 854 | \\ | ||
| 855 | \\ exit(); | ||
| 856 | \\} | ||
| 857 | \\ | ||
| 858 | \\pub fn assert(ok: bool) void { | ||
| 859 | \\ if (!ok) unreachable; // assertion failure | ||
| 860 | \\} | ||
| 861 | \\ | ||
| 862 | \\fn exit() noreturn { | ||
| 863 | \\ asm volatile ("syscall" | ||
| 864 | \\ : | ||
| 865 | \\ : [number] "{rax}" (231), | ||
| 866 | \\ [arg1] "{rdi}" (0) | ||
| 867 | \\ : "rcx", "r11", "memory" | ||
| 868 | \\ ); | ||
| 869 | \\ unreachable; | ||
| 870 | \\} | ||
| 871 | , | ||
| 872 | "", | ||
| 873 | ); | ||
| 874 | |||
| 875 | // Basic for loop | ||
| 876 | case.addCompareOutput( | ||
| 877 | \\export fn _start() noreturn { | ||
| 878 | \\ for ("hello") |_| print(); | ||
| 879 | \\ | ||
| 880 | \\ exit(); | ||
| 881 | \\} | ||
| 882 | \\ | ||
| 883 | \\fn print() void { | ||
| 884 | \\ asm volatile ("syscall" | ||
| 885 | \\ : | ||
| 886 | \\ : [number] "{rax}" (1), | ||
| 887 | \\ [arg1] "{rdi}" (1), | ||
| 888 | \\ [arg2] "{rsi}" (@ptrToInt("hello\n")), | ||
| 889 | \\ [arg3] "{rdx}" (6) | ||
| 890 | \\ : "rcx", "r11", "memory" | ||
| 891 | \\ ); | ||
| 892 | \\ return; | ||
| 893 | \\} | ||
| 894 | \\ | ||
| 895 | \\fn exit() noreturn { | ||
| 896 | \\ asm volatile ("syscall" | ||
| 897 | \\ : | ||
| 898 | \\ : [number] "{rax}" (231), | ||
| 899 | \\ [arg1] "{rdi}" (0) | ||
| 900 | \\ : "rcx", "r11", "memory" | ||
| 901 | \\ ); | ||
| 902 | \\ unreachable; | ||
| 903 | \\} | ||
| 904 | , | ||
| 905 | "hello\nhello\nhello\nhello\nhello\n", | ||
| 906 | ); | ||
| 848 | } | 907 | } |
| 849 | 908 | ||
| 850 | { | 909 | { |