diff --git a/skull/build_data.h b/skull/build_data.h index 2b443dc9..ec9016ef 100644 --- a/skull/build_data.h +++ b/skull/build_data.h @@ -15,6 +15,7 @@ typedef struct { _Bool optimize1; _Bool optimize2; _Bool optimize3; + _Bool llvm_no_verify; } BuildData; extern BuildData BUILD_DATA; diff --git a/skull/cli.c b/skull/cli.c index 386109cd..3e00f975 100644 --- a/skull/cli.c +++ b/skull/cli.c @@ -219,6 +219,9 @@ static bool parse_long_option(const char *arg) { else if (strcmp(arg, "werror") == 0) { set_bool_flag(&BUILD_DATA.werror, "--werror"); } + else if (strcmp(arg, "llvm-no-verify") == 0) { + set_bool_flag(&BUILD_DATA.llvm_no_verify, "--llvm-no-verify"); + } else { fprintf(stderr, "skull: unknown option \"--%s\"\n", arg); return true; diff --git a/skull/codegen/llvm/core.c b/skull/codegen/llvm/core.c index 68241039..9a674fdc 100644 --- a/skull/codegen/llvm/core.c +++ b/skull/codegen/llvm/core.c @@ -47,8 +47,8 @@ static Expr gen_node(const AstNode **node) { case AST_NODE_EXPR: gen_expr_func_call((*node)->expr->lhs.func_call); break; case AST_NODE_NOOP: gen_stmt_noop(&(*node)->token->location); break; - case AST_NODE_BREAK: gen_stmt_break(); break; - case AST_NODE_CONTINUE: gen_stmt_continue(); break; + case AST_NODE_BREAK: return gen_stmt_break(); + case AST_NODE_CONTINUE: return gen_stmt_continue(); default: break; } diff --git a/skull/codegen/llvm/flow.c b/skull/codegen/llvm/flow.c index 95b9d4b8..3a04f605 100644 --- a/skull/codegen/llvm/flow.c +++ b/skull/codegen/llvm/flow.c @@ -222,12 +222,24 @@ static void gen_control_if_( LLVMPositionBuilderAtEnd(SKULL_STATE_LLVM.builder, end); } -void gen_stmt_break(void) { - LLVMBuildBr(SKULL_STATE_LLVM.builder, SKULL_STATE_LLVM.current_while_end); +Expr gen_stmt_break(void) { + return (Expr){ + .value = LLVMBuildBr( + SKULL_STATE_LLVM.builder, + SKULL_STATE_LLVM.current_while_end + ), + .type = TYPE_VOID + }; } -void gen_stmt_continue(void) { - LLVMBuildBr(SKULL_STATE_LLVM.builder, SKULL_STATE_LLVM.current_while_cond); +Expr gen_stmt_continue(void) { + return (Expr){ + .value = LLVMBuildBr( + SKULL_STATE_LLVM.builder, + SKULL_STATE_LLVM.current_while_cond + ), + .type = TYPE_VOID + }; } /* diff --git a/skull/codegen/llvm/flow.h b/skull/codegen/llvm/flow.h index a2b20f40..f8920f7b 100644 --- a/skull/codegen/llvm/flow.h +++ b/skull/codegen/llvm/flow.h @@ -7,9 +7,9 @@ typedef struct Location Location; Expr gen_stmt_return(const AstNode *); Expr gen_stmt_unreachable(void); +Expr gen_stmt_break(void); +Expr gen_stmt_continue(void); void gen_stmt_implicit_main_return(const Location *); void gen_stmt_noop(const Location *); -void gen_stmt_break(void); -void gen_stmt_continue(void); void gen_control_while(const AstNode *); void gen_control_if(const AstNode **); diff --git a/skull/codegen/llvm/write.c b/skull/codegen/llvm/write.c index 17a21429..78d212a7 100644 --- a/skull/codegen/llvm/write.c +++ b/skull/codegen/llvm/write.c @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -21,6 +22,7 @@ #include "skull/common/str.h" static bool create_ll_file(const char *); +static bool verify_llvm(void); static bool optimize_llvm(void); static int run_llc(void); static int run_cc(char *); @@ -34,6 +36,10 @@ static int check_directory(char *); Write LLVM code to `filename`, return whether error occured. */ bool write_file_llvm(const char *filename) { + if (BUILD_DATA.debug) LLVMDIBuilderFinalize(DEBUG_INFO.builder); + + if (!BUILD_DATA.llvm_no_verify && verify_llvm()) return true; + if (BUILD_DATA.optimize1 || BUILD_DATA.optimize2 || BUILD_DATA.optimize3) { if (optimize_llvm()) return true; } @@ -51,6 +57,24 @@ bool write_file_llvm(const char *filename) { return err || run_cc(binary_name); } +static bool verify_llvm(void) { + char *err_msg = NULL; + + const bool err = LLVMVerifyModule( + SKULL_STATE_LLVM.module, + LLVMReturnStatusAction, + &err_msg + ); + + if (err) { + fprintf(stderr, "skull: error while verifying LLVM: %s\n", err_msg); + } + + LLVMDisposeMessage(err_msg); + + return err; +} + static bool optimize_llvm(void) { LLVMInitializeAllTargetInfos(); @@ -100,8 +124,6 @@ static bool optimize_llvm(void) { } static bool create_ll_file(const char *filename) { - if (BUILD_DATA.debug) LLVMDIBuilderFinalize(DEBUG_INFO.builder); - if (strcmp(filename, "-") == 0) { char *msg = LLVMPrintModuleToString(SKULL_STATE_LLVM.module); printf("%s", msg); diff --git a/test/sh/flow/break.sk.ll b/test/sh/flow/break.sk.ll index 69630d1e..f895d442 100644 --- a/test/sh/flow/break.sk.ll +++ b/test/sh/flow/break.sk.ll @@ -5,12 +5,11 @@ define i64 @.break() { entry: br label %while_cond -while_cond: ; preds = %while_loop, %entry +while_cond: ; preds = %entry br i1 true, label %while_loop, label %while_end while_loop: ; preds = %while_cond br label %while_end - br label %while_cond while_end: ; preds = %while_loop, %while_cond ret i64 0 diff --git a/test/sh/flow/continue.sk.ll b/test/sh/flow/continue.sk.ll index 14cb6d8c..20a0a761 100644 --- a/test/sh/flow/continue.sk.ll +++ b/test/sh/flow/continue.sk.ll @@ -5,12 +5,11 @@ define i64 @.continue() { entry: br label %while_cond -while_cond: ; preds = %while_loop, %while_loop, %entry +while_cond: ; preds = %while_loop, %entry br i1 true, label %while_loop, label %while_end while_loop: ; preds = %while_cond br label %while_cond - br label %while_cond while_end: ; preds = %while_cond ret i64 0 diff --git a/test/sh/main.sh b/test/sh/main.sh index 5f6e3709..0fb9784d 100755 --- a/test/sh/main.sh +++ b/test/sh/main.sh @@ -130,6 +130,7 @@ test_skull "duplicate_arg.sh -O2" "-O2 -O2" test_skull "duplicate_arg.sh -O3" "-O3 -O3" test_skull "duplicate_arg.sh --c-backend" "--c-backend --c-backend" test_skull "duplicate_arg.sh --werror" "--werror --werror" +test_skull "duplicate_arg.sh --llvm-no-verify" "--llvm-no-verify --llvm-no-verify" test_skull "warn_dash_dash_no_args.sh" "--" test_skull "dash_o_expect_filename.sh" "-o" test_skull "dash_o_no_binary.sh" "./test/sh/skull/dummy.sk -o -"