Adding $unreachable

This commit is contained in:
Christoffer Lerno
2020-08-01 23:57:23 +02:00
committed by Christoffer Lerno
parent 009ccfd730
commit 31d2c15dba
9 changed files with 93 additions and 10 deletions

View File

@@ -2,19 +2,18 @@ module baz;
import gen;
extern func int printf(char *hello, ...);
extern func void blurg();
public func void runBaz()
{
int x = printf("Baz func\n");
int y = printf("FOek");
assert(x > 0 && y > 0);
int i = printf("hello");
int z = printf("Foefe\n");
x = printf("Baz func\n");
y = printf("FOek");
if (i > 0) blurg();
assert(x > 0 && y > 0 && printf("Fejei") > 0);
if (i > 0) return;
$unreachable;
}

View File

@@ -1085,6 +1085,9 @@ static void fprint_ast_recursive(Context *context, FILE *file, Ast *ast, int ind
case AST_NOP_STMT:
DUMP("(nop)");
return;
case AST_UNREACHABLE_STMT:
DUMP("(unreachable)");
return;
case AST_VOLATILE_STMT:
DUMP("(volatile");
DUMPAST(ast->volatile_stmt);

View File

@@ -76,6 +76,7 @@ typedef enum
AST_RETURN_STMT,
AST_SWITCH_STMT,
AST_NEXT_STMT,
AST_UNREACHABLE_STMT,
AST_VOLATILE_STMT,
AST_WHILE_STMT,
AST_SCOPED_STMT,
@@ -412,6 +413,7 @@ typedef enum
TOKEN_TRY,
TOKEN_TYPEDEF,
TOKEN_UNION,
TOKEN_CT_UNREACHABLE,
TOKEN_UNTIL,
TOKEN_VAR, // Reserved
TOKEN_VOLATILE,

View File

@@ -847,6 +847,17 @@ static inline void gencontext_emit_assert_stmt(GenContext *context, Ast *ast)
gencontext_emit_assume(context, ast->assert_stmt.expr);
}
static inline void gencontext_emit_unreachable_stmt(GenContext *context, Ast *ast)
{
// TODO emit message
gencontext_emit_call_intrinsic(context, trap_intrinsic_id, NULL, 0, NULL, 0);
LLVMBuildUnreachable(context->builder);
LLVMBasicBlockRef block = gencontext_create_free_block(context, "unreachable_block");
context->current_block = NULL;
context->current_block_is_target = false;
gencontext_emit_block(context, block);
}
void gencontext_emit_expr_stmt(GenContext *context, Ast *ast)
{
if (ast->expr_stmt->failable)
@@ -1003,13 +1014,15 @@ void gencontext_emit_stmt(GenContext *context, Ast *ast)
case AST_CT_ELSE_STMT:
case AST_CT_FOR_STMT:
case AST_CT_SWITCH_STMT:
case AST_CASE_STMT:
case AST_DEFAULT_STMT:
UNREACHABLE
case AST_SWITCH_STMT:
gencontext_emit_switch(context, ast);
break;
case AST_CASE_STMT:
case AST_DEFAULT_STMT:
TODO
case AST_UNREACHABLE_STMT:
gencontext_emit_unreachable_stmt(context, ast);
break;
case AST_VOLATILE_STMT:
TODO
}

View File

@@ -6,6 +6,8 @@
#include "parser_internal.h"
Ast *parse_unreachable_stmt(Context *context);
#pragma mark --- Internal functions
@@ -913,6 +915,8 @@ Ast *parse_stmt(Context *context)
return parse_ct_for_stmt(context);
case TOKEN_VOLATILE:
return parse_volatile_stmt(context);
case TOKEN_CT_UNREACHABLE:
return parse_unreachable_stmt(context);
case TOKEN_STAR:
case TOKEN_AMP:
case TOKEN_INTEGER:
@@ -1034,6 +1038,14 @@ Ast *parse_stmt(Context *context)
UNREACHABLE
}
Ast *parse_unreachable_stmt(Context *context)
{
Ast *ast = AST_NEW_TOKEN(AST_UNREACHABLE_STMT, context->tok);
advance_and_verify(context, TOKEN_CT_UNREACHABLE);
TRY_CONSUME_EOS_OR(poisoned_ast);
return ast;
}
Ast *parse_jump_stmt_no_eos(Context *context)
{
switch (context->tok.type)

View File

@@ -3395,6 +3395,8 @@ static Ast *ast_copy_from_macro(Context *context, Ast *source)
MACRO_COPY_EXPR(ast->try_stmt.decl_expr);
MACRO_COPY_AST(ast->try_stmt.body);
return ast;
case AST_UNREACHABLE_STMT:
return ast;
case AST_VOLATILE_STMT:
TODO
return ast;

View File

@@ -178,6 +178,12 @@ static inline bool sema_analyse_return_stmt(Context *context, Ast *statement)
return true;
}
static inline bool sema_analyse_unreachable_stmt(Context *context, Ast *statement)
{
context->current_scope->jump_end = true;
return true;
}
static inline bool sema_analyse_decl_expr_list(Context *context, Expr *expr)
{
assert(expr->expr_kind == EXPR_DECL_LIST);
@@ -1286,6 +1292,11 @@ static inline bool sema_analyse_statement_inner(Context *context, Ast *statement
}
if (context->current_scope->jump_end && !context->current_scope->allow_dead_code)
{
if (statement->ast_kind == AST_UNREACHABLE_STMT)
{
context->current_scope->allow_dead_code = true;
return true;
}
//SEMA_ERROR(statement, "This code will never execute.");
context->current_scope->allow_dead_code = true;
//return false;
@@ -1341,10 +1352,13 @@ static inline bool sema_analyse_statement_inner(Context *context, Ast *statement
return sema_analyse_switch_stmt(context, statement);
case AST_NEXT_STMT:
return sema_analyse_next_stmt(context, statement);
case AST_UNREACHABLE_STMT:
return sema_analyse_unreachable_stmt(context, statement);
case AST_VOLATILE_STMT:
return sema_analyse_volatile_stmt(context, statement);
case AST_WHILE_STMT:
return sema_analyse_while_stmt(context, statement);
case AST_CT_ELIF_STMT:
case AST_CT_ELSE_STMT:
UNREACHABLE

View File

@@ -344,6 +344,8 @@ const char *token_type_to_string(TokenType type)
return "$if";
case TOKEN_CT_SWITCH:
return "$switch";
case TOKEN_CT_UNREACHABLE:
return "$unreachable";
case TOKEN_EOF:
return "EOF";

View File

@@ -0,0 +1,36 @@
public func int foo()
{
return 1;
}
public func void test()
{
int x = foo();
if (x > 0) return;
$unreachable;
x++;
}
// #expect: unreachable.ll
%x = alloca i32
%0 = call i32 @unreachable.foo()
store i32 %0, i32* %x
%1 = load i32, i32* %x
%gt = icmp sgt i32 %1, 0
br i1 %gt, label %if.then, label %if.exit
if.then:
ret void
if.exit:
call void @llvm.trap()
unreachable
unreachable_block:
%2 = load i32, i32* %x
%add = add nsw i32 %2, 1
store i32 %add, i32* %x
ret void