From 015f2868f60c3a5269009ca474244a6c0e784734 Mon Sep 17 00:00:00 2001 From: isuckatcs <65320245+isuckatcs@users.noreply.github.com> Date: Fri, 5 Jul 2024 20:25:18 +0200 Subject: [PATCH] [Codegen] fix bugprone return block emission --- src/codegen.cpp | 7 +- test/codegen/condition_empty_merge.al | 4 +- test/codegen/multiple_return.al | 2 +- test/codegen/multiple_return_if.al | 2 +- test/codegen/multiple_return_while.al | 2 +- test/codegen/return.al | 99 +++++++++++++++++++++++++++ test/codegen/while_empty_exit.al | 4 +- 7 files changed, 107 insertions(+), 13 deletions(-) create mode 100644 test/codegen/return.al diff --git a/src/codegen.cpp b/src/codegen.cpp index ffa93f4..2796055 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -333,14 +333,8 @@ void Codegen::generateBlock(const ResolvedBlock &block) { break; } } - - // FIXME: This should disappear with return optimization. - if (const llvm::BasicBlock *bb = builder.GetInsertBlock(); - bb && bb->empty() && !retBlock->hasNPredecessors(0)) - builder.CreateUnreachable(); } -// FIXME: Optimize return stmt emission. void Codegen::generateFunctionBody(const ResolvedFunctionDecl &functionDecl) { auto *function = module->getFunction(functionDecl.identifier); auto *bb = llvm::BasicBlock::Create(context, "", function); @@ -370,6 +364,7 @@ void Codegen::generateFunctionBody(const ResolvedFunctionDecl &functionDecl) { generateBlock(*functionDecl.body); if (retBlock->hasNPredecessorsOrMore(1)) { + builder.CreateBr(retBlock); retBlock->insertInto(function); builder.SetInsertPoint(retBlock); } diff --git a/test/codegen/condition_empty_merge.al b/test/codegen/condition_empty_merge.al index 5e107bb..59be40a 100644 --- a/test/codegen/condition_empty_merge.al +++ b/test/codegen/condition_empty_merge.al @@ -23,8 +23,8 @@ fn main(): void { // CHECK-NEXT: br label %return // CHECK-NEXT: // CHECK-NEXT: merge: ; preds = , %0 -// CHECK-NEXT: unreachable +// CHECK-NEXT: br label %return // CHECK-NEXT: -// CHECK-NEXT: return: ; preds = %then +// CHECK-NEXT: return: ; preds = %merge, %then // CHECK-NEXT: ret void // CHECK-NEXT: } diff --git a/test/codegen/multiple_return.al b/test/codegen/multiple_return.al index 36c7a5e..624631a 100644 --- a/test/codegen/multiple_return.al +++ b/test/codegen/multiple_return.al @@ -10,6 +10,6 @@ fn main(): void { // CHECK: define void @__builtin_main() { // CHECK-NEXT: br label %return // CHECK-NEXT: -// CHECK-NEXT: return: ; preds = %0 +// CHECK-NEXT: return: ; preds = , %0 // CHECK-NEXT: ret void // CHECK-NEXT: } diff --git a/test/codegen/multiple_return_if.al b/test/codegen/multiple_return_if.al index b6ca02d..436c929 100644 --- a/test/codegen/multiple_return_if.al +++ b/test/codegen/multiple_return_if.al @@ -35,7 +35,7 @@ fn foo(x: number): number { // CHECK-NEXT: store double 5.200000e+00, double* %retval, align 8 // CHECK-NEXT: br label %return // CHECK-NEXT: -// CHECK-NEXT: return: ; preds = %merge5, %then3, %then +// CHECK-NEXT: return: ; preds = , %merge5, %then3, %then // CHECK-NEXT: %5 = load double, double* %retval, align 8 // CHECK-NEXT: ret double %5 diff --git a/test/codegen/multiple_return_while.al b/test/codegen/multiple_return_while.al index 2ef62e6..42361a8 100644 --- a/test/codegen/multiple_return_while.al +++ b/test/codegen/multiple_return_while.al @@ -38,7 +38,7 @@ fn foo(x: number): number { // CHECK-NEXT: store double 5.000000e+00, double* %retval, align 8 // CHECK-NEXT: br label %return // CHECK-NEXT: -// CHECK-NEXT: return: ; preds = %whileExit, %merge, %then +// CHECK-NEXT: return: ; preds = , %whileExit, %merge, %then // CHECK-NEXT: %8 = load double, double* %retval, align 8 // CHECK-NEXT: ret double %8 diff --git a/test/codegen/return.al b/test/codegen/return.al new file mode 100644 index 0000000..6782254 --- /dev/null +++ b/test/codegen/return.al @@ -0,0 +1,99 @@ +// RUN: compiler %s -llvm-dump 2>&1 | filecheck %s +// RUN: compiler %s -o return && ./return | ( ! grep ^ ) +fn main(): void {} + +fn noInsertPoint(): void { + return; +} +// CHECK: define void @noInsertPoint() { +// CHECK-NEXT: br label %return +// CHECK-NEXT: +// CHECK-NEXT: return: ; preds = , %0 +// CHECK-NEXT: ret void +// CHECK-NEXT: } + +fn insertPointEmptyBlock(): void { + if 1.0 { + return; + } +} +// CHECK: define void @insertPointEmptyBlock() { +// CHECK-NEXT: br i1 true, label %then, label %merge +// CHECK-NEXT: +// CHECK-NEXT: then: ; preds = %0 +// CHECK-NEXT: br label %return +// CHECK-NEXT: +// CHECK-NEXT: merge: ; preds = , %0 +// CHECK-NEXT: br label %return +// CHECK-NEXT: +// CHECK-NEXT: return: ; preds = %merge, %then +// CHECK-NEXT: ret void +// CHECK-NEXT: } + +fn insertPointEmptyBlock2(): void { + while 1.0 { + return; + } +} +// CHECK: define void @insertPointEmptyBlock2() { +// CHECK-NEXT: br label %whileCond +// CHECK-NEXT: +// CHECK-NEXT: whileCond: ; preds = , %0 +// CHECK-NEXT: br i1 true, label %whileBody, label %whileExit +// CHECK-NEXT: +// CHECK-NEXT: whileBody: ; preds = %whileCond +// CHECK-NEXT: br label %return +// CHECK-NEXT: +// CHECK-NEXT: whileExit: ; preds = %whileCond +// CHECK-NEXT: br label %return +// CHECK-NEXT: +// CHECK-NEXT: return: ; preds = %whileExit, %whileBody +// CHECK-NEXT: ret void +// CHECK-NEXT: } + +fn insertPointNonEmptyBlock(): void { + if 1.0 { + return; + } + + let x: number = 1.0; +} +// CHECK: define void @insertPointNonEmptyBlock() { +// CHECK-NEXT: %x = alloca double, align 8 +// CHECK-NEXT: br i1 true, label %then, label %merge +// CHECK-NEXT: +// CHECK-NEXT: then: ; preds = %0 +// CHECK-NEXT: br label %return +// CHECK-NEXT: +// CHECK-NEXT: merge: ; preds = , %0 +// CHECK-NEXT: store double 1.000000e+00, double* %x, align 8 +// CHECK-NEXT: br label %return +// CHECK-NEXT: +// CHECK-NEXT: return: ; preds = %merge, %then +// CHECK-NEXT: ret void +// CHECK-NEXT: } + +fn insertPointNonEmptyBlock2(): void { + while 1.0 { + return; + } + + let x: number = 1.0; +} +// CHECK: define void @insertPointNonEmptyBlock2() { +// CHECK-NEXT: %x = alloca double, align 8 +// CHECK-NEXT: br label %whileCond +// CHECK-NEXT: +// CHECK-NEXT: whileCond: ; preds = , %0 +// CHECK-NEXT: br i1 true, label %whileBody, label %whileExit +// CHECK-NEXT: +// CHECK-NEXT: whileBody: ; preds = %whileCond +// CHECK-NEXT: br label %return +// CHECK-NEXT: +// CHECK-NEXT: whileExit: ; preds = %whileCond +// CHECK-NEXT: store double 1.000000e+00, double* %x, align 8 +// CHECK-NEXT: br label %return +// CHECK-NEXT: +// CHECK-NEXT: return: ; preds = %whileExit, %whileBody +// CHECK-NEXT: ret void +// CHECK-NEXT: } diff --git a/test/codegen/while_empty_exit.al b/test/codegen/while_empty_exit.al index 9247189..dbea9d4 100644 --- a/test/codegen/while_empty_exit.al +++ b/test/codegen/while_empty_exit.al @@ -21,9 +21,9 @@ fn foo(x: number): void { // CHECK-NEXT: br label %return // CHECK-NEXT: // CHECK-NEXT: whileExit: ; preds = %whileCond -// CHECK-NEXT: unreachable +// CHECK-NEXT: br label %return // CHECK-NEXT: -// CHECK-NEXT: return: ; preds = %whileBody +// CHECK-NEXT: return: ; preds = %whileExit, %whileBody // CHECK-NEXT: ret void // CHECK-NEXT: }