Commit a54ccd8537

Andrew Kelley <andrew@ziglang.org>
2020-12-29 02:43:01
stage2: C backend: implement `@breakpoint` and clean up test harness
1 parent 37f04d6
Changed files (4)
src
codegen
link
test
stage2
src/codegen/c.zig
@@ -232,7 +232,7 @@ pub fn generate(file: *C, decl: *Decl) !void {
                     .retvoid => try genRetVoid(file),
                     .arg => try genArg(&ctx),
                     .dbg_stmt => try genDbgStmt(&ctx, inst.castTag(.dbg_stmt).?),
-                    .breakpoint => try genBreak(&ctx, inst.castTag(.breakpoint).?),
+                    .breakpoint => try genBreakpoint(file, inst.castTag(.breakpoint).?),
                     .unreach => try genUnreach(file, inst.castTag(.unreach).?),
                     .intcast => try genIntCast(&ctx, file, inst.castTag(.intcast).?),
                     else => |e| return ctx.fail(decl.src(), "TODO: C backend: implement codegen for {}", .{e}),
@@ -447,8 +447,8 @@ fn genDbgStmt(ctx: *Context, inst: *Inst.NoOp) !?[]u8 {
     return null;
 }
 
-fn genBreak(ctx: *Context, inst: *Inst.NoOp) !?[]u8 {
-    // TODO ??
+fn genBreakpoint(file: *C, inst: *Inst.NoOp) !?[]u8 {
+    try file.main.writer().writeAll("zig_breakpoint();\n");
     return null;
 }
 
src/link/cbe.h
@@ -1,5 +1,4 @@
 #if __STDC_VERSION__ >= 199901L
-// C99 or newer
 #include <stdbool.h>
 #else
 #define bool unsigned char
@@ -17,12 +16,28 @@
 #define zig_noreturn
 #endif
 
-#if __GNUC__
+#if defined(__GNUC__)
 #define zig_unreachable() __builtin_unreachable()
 #else
 #define zig_unreachable()
 #endif
 
+#if defined(_MSC_VER)
+#define zig_breakpoint __debugbreak()
+#else
+#if defined(__MINGW32__) || defined(__MINGW64__)
+#define zig_breakpoint __debugbreak()
+#elif defined(__clang__)
+#define zig_breakpoint __builtin_debugtrap()
+#elif defined(__GNUC__)
+#define zig_breakpoint __builtin_trap()
+#elif defined(__i386__) || defined(__x86_64__)
+#define zig_breakpoint __asm__ volatile("int $0x03");
+#else
+#define zig_breakpoint raise(SIGTRAP)
+#endif
+#endif
+
 #include <stdint.h>
 #define int128_t __int128
 #define uint128_t unsigned __int128
src/test.zig
@@ -646,35 +646,16 @@ pub const TestContext = struct {
                     defer file.close();
                     var out = file.reader().readAllAlloc(arena, 1024 * 1024) catch @panic("Unable to read headeroutput!");
 
-                    if (expected_output.len != out.len) {
-                        std.debug.print("\nTransformed header length differs:\n================\nExpected:\n================\n{}\n================\nFound:\n================\n{}\n================\nTest failed.\n", .{ expected_output, out });
-                        std.process.exit(1);
-                    }
-                    for (expected_output) |e, i| {
-                        if (out[i] != e) {
-                            std.debug.print("\nTransformed header differs:\n================\nExpected:\n================\n{}\n================\nFound:\n================\n{}\n================\nTest failed.\n", .{ expected_output, out });
-                            std.process.exit(1);
-                        }
-                    }
+                    std.testing.expectEqualStrings(expected_output, out);
                 },
                 .Transformation => |expected_output| {
                     if (case.cbe) {
                         // The C file is always closed after an update, because we don't support
-                        // incremental updates
+                        // incremental updates.
                         var file = try tmp.dir.openFile(bin_name, .{ .read = true });
                         defer file.close();
                         var out = file.reader().readAllAlloc(arena, 1024 * 1024) catch @panic("Unable to read C output!");
-
-                        if (expected_output.len != out.len) {
-                            std.debug.print("\nTransformed C length differs:\n================\nExpected:\n================\n{}\n================\nFound:\n================\n{}\n================\nTest failed.\n", .{ expected_output, out });
-                            std.process.exit(1);
-                        }
-                        for (expected_output) |e, i| {
-                            if (out[i] != e) {
-                                std.debug.print("\nTransformed C differs:\n================\nExpected:\n================\n{}\n================\nFound:\n================\n{}\n================\nTest failed.\n", .{ expected_output, out });
-                                std.process.exit(1);
-                            }
-                        }
+                        std.testing.expectEqualStrings(expected_output, out);
                     } else {
                         update_node.setEstimatedTotalItems(5);
                         var emit_node = update_node.start("emit", 0);
@@ -694,16 +675,7 @@ pub const TestContext = struct {
                         test_node.activate();
                         defer test_node.end();
 
-                        if (expected_output.len != out_zir.items.len) {
-                            std.debug.print("{}\nTransformed ZIR length differs:\n================\nExpected:\n================\n{}\n================\nFound:\n================\n{}\n================\nTest failed.\n", .{ case.name, expected_output, out_zir.items });
-                            std.process.exit(1);
-                        }
-                        for (expected_output) |e, i| {
-                            if (out_zir.items[i] != e) {
-                                std.debug.print("{}\nTransformed ZIR differs:\n================\nExpected:\n================\n{}\n================\nFound:\n================\n{}\n================\nTest failed.\n", .{ case.name, expected_output, out_zir.items });
-                                std.process.exit(1);
-                            }
-                        }
+                        std.testing.expectEqualStrings(expected_output, out_zir.items);
                     }
                 },
                 .Error => |e| {
test/stage2/cbe.zig
@@ -15,6 +15,7 @@ pub fn addCases(ctx: *TestContext) !void {
         \\}
     ,
         \\zig_noreturn void _start(void) {
+        \\    zig_breakpoint();
         \\    zig_unreachable();
         \\}
         \\
@@ -41,6 +42,7 @@ pub fn addCases(ctx: *TestContext) !void {
         \\}
         \\
         \\zig_noreturn void main(void) {
+        \\    zig_breakpoint();
         \\    zig_unreachable();
         \\}
         \\
@@ -61,8 +63,6 @@ pub fn addCases(ctx: *TestContext) !void {
         \\    exitGood();
         \\}
     ,
-        \\#include <stddef.h>
-        \\
         \\zig_noreturn void exitGood(void);
         \\
         \\const char *const exitGood__anon_0 = "{rax}";
@@ -74,9 +74,10 @@ pub fn addCases(ctx: *TestContext) !void {
         \\}
         \\
         \\zig_noreturn void exitGood(void) {
-        \\    register size_t rax_constant __asm__("rax") = 231;
-        \\    register size_t rdi_constant __asm__("rdi") = 0;
+        \\    register uintptr_t rax_constant __asm__("rax") = 231;
+        \\    register uintptr_t rdi_constant __asm__("rdi") = 0;
         \\    __asm volatile ("syscall" :: ""(rax_constant), ""(rdi_constant));
+        \\    zig_breakpoint();
         \\    zig_unreachable();
         \\}
         \\
@@ -96,9 +97,7 @@ pub fn addCases(ctx: *TestContext) !void {
         \\}
         \\
     ,
-        \\#include <stddef.h>
-        \\
-        \\zig_noreturn void exit(size_t arg0);
+        \\zig_noreturn void exit(uintptr_t arg0);
         \\
         \\const char *const exit__anon_0 = "{rax}";
         \\const char *const exit__anon_1 = "{rdi}";
@@ -108,10 +107,11 @@ pub fn addCases(ctx: *TestContext) !void {
         \\    exit(0);
         \\}
         \\
-        \\zig_noreturn void exit(size_t arg0) {
-        \\    register size_t rax_constant __asm__("rax") = 231;
-        \\    register size_t rdi_constant __asm__("rdi") = arg0;
+        \\zig_noreturn void exit(uintptr_t arg0) {
+        \\    register uintptr_t rax_constant __asm__("rax") = 231;
+        \\    register uintptr_t rdi_constant __asm__("rdi") = arg0;
         \\    __asm volatile ("syscall" :: ""(rax_constant), ""(rdi_constant));
+        \\    zig_breakpoint();
         \\    zig_unreachable();
         \\}
         \\
@@ -131,7 +131,6 @@ pub fn addCases(ctx: *TestContext) !void {
         \\}
         \\
     ,
-        \\#include <stddef.h>
         \\#include <stdint.h>
         \\
         \\zig_noreturn void exit(uint8_t arg0);
@@ -145,10 +144,11 @@ pub fn addCases(ctx: *TestContext) !void {
         \\}
         \\
         \\zig_noreturn void exit(uint8_t arg0) {
-        \\    const size_t __temp_0 = (size_t)arg0;
-        \\    register size_t rax_constant __asm__("rax") = 231;
-        \\    register size_t rdi_constant __asm__("rdi") = __temp_0;
+        \\    const uintptr_t __temp_0 = (uintptr_t)arg0;
+        \\    register uintptr_t rax_constant __asm__("rax") = 231;
+        \\    register uintptr_t rdi_constant __asm__("rdi") = __temp_0;
         \\    __asm volatile ("syscall" :: ""(rax_constant), ""(rdi_constant));
+        \\    zig_breakpoint();
         \\    zig_unreachable();
         \\}
         \\
@@ -172,7 +172,6 @@ pub fn addCases(ctx: *TestContext) !void {
         \\}
         \\
     ,
-        \\#include <stddef.h>
         \\#include <stdint.h>
         \\
         \\zig_noreturn void exitMath(uint8_t arg0);
@@ -193,10 +192,11 @@ pub fn addCases(ctx: *TestContext) !void {
         \\}
         \\
         \\zig_noreturn void exit(uint8_t arg0) {
-        \\    const size_t __temp_0 = (size_t)arg0;
-        \\    register size_t rax_constant __asm__("rax") = 231;
-        \\    register size_t rdi_constant __asm__("rdi") = __temp_0;
+        \\    const uintptr_t __temp_0 = (uintptr_t)arg0;
+        \\    register uintptr_t rax_constant __asm__("rax") = 231;
+        \\    register uintptr_t rdi_constant __asm__("rdi") = __temp_0;
         \\    __asm volatile ("syscall" :: ""(rax_constant), ""(rdi_constant));
+        \\    zig_breakpoint();
         \\    zig_unreachable();
         \\}
         \\
@@ -220,7 +220,6 @@ pub fn addCases(ctx: *TestContext) !void {
         \\}
         \\
     ,
-        \\#include <stddef.h>
         \\#include <stdint.h>
         \\
         \\zig_noreturn void exitMath(uint8_t arg0);
@@ -241,10 +240,11 @@ pub fn addCases(ctx: *TestContext) !void {
         \\}
         \\
         \\zig_noreturn void exit(uint8_t arg0) {
-        \\    const size_t __temp_0 = (size_t)arg0;
-        \\    register size_t rax_constant __asm__("rax") = 231;
-        \\    register size_t rdi_constant __asm__("rdi") = __temp_0;
+        \\    const uintptr_t __temp_0 = (uintptr_t)arg0;
+        \\    register uintptr_t rax_constant __asm__("rax") = 231;
+        \\    register uintptr_t rdi_constant __asm__("rdi") = __temp_0;
         \\    __asm volatile ("syscall" :: ""(rax_constant), ""(rdi_constant));
+        \\    zig_breakpoint();
         \\    zig_unreachable();
         \\}
         \\
@@ -276,9 +276,7 @@ pub fn addCases(ctx: *TestContext) !void {
     ctx.h("header with usize param function", linux_x64,
         \\export fn start(a: usize) void{}
     ,
-        \\#include <stddef.h>
-        \\
-        \\void start(size_t arg0);
+        \\void start(uintptr_t arg0);
         \\
     );
     ctx.h("header with bool param function", linux_x64,
@@ -308,10 +306,9 @@ pub fn addCases(ctx: *TestContext) !void {
     ctx.h("header with multiple includes", linux_x64,
         \\export fn start(a: u32, b: usize) void{}
     ,
-        \\#include <stddef.h>
         \\#include <stdint.h>
         \\
-        \\void start(uint32_t arg0, size_t arg1);
+        \\void start(uint32_t arg0, uintptr_t arg1);
         \\
     );
 }