Fix issues with @jump on empty default or only default #1893 #1894

This commit is contained in:
Christoffer Lerno
2025-01-26 15:38:24 +01:00
parent 1f1c445a76
commit 26dc88e096
4 changed files with 79 additions and 3 deletions

View File

@@ -29,7 +29,7 @@
- Fix bug where .min/.max would fail on a distinct int #1888.
- Fix issue where compile time declarations in expression list would not be handled properly.
- Issue where trailing body argument was allowed without type even though the definition specified it #1879.
- Fix issues with @jump on empty `default` or only `default` #1893 #1894
### Stdlib changes
- Added '%h' and '%H' for printing out binary data in hexadecimal using the formatter.
- Added weakly linked `__powidf2`

View File

@@ -777,6 +777,7 @@ static LLVMValueRef llvm_emit_switch_jump_stmt(GenContext *c,
LLVMBasicBlockRef default_block,
BEValue *switch_value)
{
ASSERT_SPAN(switch_ast, min_index > -1);
unsigned case_count = vec_size(cases);
BEValue min_val;
llvm_emit_expr(c, &min_val, exprptr(cases[min_index]->case_stmt.expr));
@@ -848,6 +849,7 @@ static void llvm_emit_switch_jump_table(GenContext *c,
Ast *case_ast = cases[i];
if (case_ast->ast_kind == AST_DEFAULT_STMT)
{
if (!case_ast->case_stmt.body) continue;
default_block = case_ast->case_stmt.backend_block;
default_index = i;
continue;
@@ -914,7 +916,7 @@ static void llvm_emit_switch_jump_table(GenContext *c,
if (!case_stmt->case_stmt.body) continue;
LLVMAddDestination(instr, block);
}
if (!case_stmt->case_stmt.body) continue;
llvm_emit_block(c, block);
llvm_emit_stmt(c, case_stmt->case_stmt.body);
llvm_emit_br(c, exit_block);

View File

@@ -2533,7 +2533,11 @@ static bool sema_analyse_switch_body(SemaContext *context, Ast *statement, Sourc
RETURN_SEMA_ERROR(statement, "The switch cannot use a jump table size of the table would exceed "
"the maximum allowed (%u), please remove '@jump'.", compiler.build.switchjump_max_size);
}
}
// Do not generate a jump table if we only have a default statement.
if (default_case && case_count == 1)
{
statement->flow.jump = false;
}
}

View File

@@ -0,0 +1,70 @@
// #target: macos-aarch64
module test;
fn void test1()
{
switch (0) @jump
{
case 0:
break;
default:
}
}
enum Foo { A, B, }
fn void main()
{
test1();
switch (Foo.A) @jump
{
default:
break;
}
}
/* #expect: test.ll
@jumptable = private unnamed_addr constant [1 x ptr] [ptr blockaddress(@test.test1, %switch.case)], align 4
define void @test.test1() #0 {
entry:
%switch = alloca i32, align 4
store i32 0, ptr %switch, align 4
br label %switch.entry
switch.entry: ; preds = %entry
%0 = load i32, ptr %switch, align 4
%1 = icmp ugt i32 %0, 0
br i1 %1, label %switch.exit, label %jumpblock
jumpblock: ; preds = %switch.entry
%ptroffset = getelementptr inbounds [8 x i8], ptr @jumptable, i32 %0
%target = load ptr, ptr %ptroffset, align 8
indirectbr ptr %target, [label %switch.case]
switch.case: ; preds = %jumpblock
br label %switch.exit
switch.exit: ; preds = %switch.case, %switch.entry
ret void
}
define void @test.main() #0 {
entry:
%switch = alloca i32, align 4
call void @test.test1()
store i32 0, ptr %switch, align 4
br label %switch.entry
switch.entry: ; preds = %entry
%0 = load i32, ptr %switch, align 4
switch i32 %0, label %switch.default [
]
switch.default: ; preds = %switch.entry
br label %switch.exit
switch.exit: ; preds = %switch.default
ret void
}