Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions include/codegen.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ class Codegen {
llvm::Value *storeValue(llvm::Value *val, llvm::Value *ptr, const Type &type);
llvm::Value *doubleToBool(llvm::Value *v);
llvm::Value *boolToDouble(llvm::Value *v);
void breakIntoBB(llvm::BasicBlock *targetBB);

llvm::Function *getCurrentFunction();
llvm::AllocaInst *allocateStackVariable(const std::string_view identifier,
Expand Down
35 changes: 21 additions & 14 deletions src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,13 @@ llvm::Value *Codegen::generateIfStmt(const ResolvedIfStmt &stmt) {
trueBB->insertInto(function);
builder.SetInsertPoint(trueBB);
generateBlock(*stmt.trueBlock);
builder.CreateBr(exitBB);
breakIntoBB(exitBB);

if (stmt.falseBlock) {
elseBB->insertInto(function);

builder.SetInsertPoint(elseBB);
generateBlock(*stmt.falseBlock);
builder.CreateBr(exitBB);
breakIntoBB(exitBB);
}

exitBB->insertInto(function);
Expand All @@ -92,7 +91,7 @@ llvm::Value *Codegen::generateWhileStmt(const ResolvedWhileStmt &stmt) {

builder.SetInsertPoint(body);
generateBlock(*stmt.body);
builder.CreateBr(header);
breakIntoBB(header);

builder.SetInsertPoint(exit);
return nullptr;
Expand Down Expand Up @@ -120,7 +119,8 @@ llvm::Value *Codegen::generateReturnStmt(const ResolvedReturnStmt &stmt) {
storeValue(generateExpr(*stmt.expr), retVal, stmt.expr->type);

assert(retBB && "function with return stmt doesn't have a return block");
return builder.CreateBr(retBB);
breakIntoBB(retBB);
return nullptr;
}

llvm::Value *Codegen::generateMemberExpr(const ResolvedMemberExpr &memberExpr,
Expand Down Expand Up @@ -290,6 +290,9 @@ Codegen::generateBinaryOperator(const ResolvedBinaryOperator &binop) {

builder.SetInsertPoint(rhsBB);
llvm::Value *rhs = doubleToBool(generateExpr(*binop.rhs));

assert(!builder.GetInsertBlock()->getTerminator() &&
"a binop terminated the current block");
builder.CreateBr(mergeBB);

rhsBB = builder.GetInsertBlock();
Expand Down Expand Up @@ -362,6 +365,15 @@ llvm::Value *Codegen::boolToDouble(llvm::Value *v) {
return builder.CreateUIToFP(v, builder.getDoubleTy(), "to.double");
}

void Codegen::breakIntoBB(llvm::BasicBlock *targetBB) {
llvm::BasicBlock *currentBB = builder.GetInsertBlock();

if (currentBB && !currentBB->getTerminator())
builder.CreateBr(targetBB);

builder.ClearInsertionPoint();
}

llvm::Function *Codegen::getCurrentFunction() {
return builder.GetInsertBlock()->getParent();
};
Expand Down Expand Up @@ -405,15 +417,10 @@ void Codegen::generateBlock(const ResolvedBlock &block) {
for (auto &&stmt : block.statements) {
generateStmt(*stmt);

// After a return statement we clear the insertion point, so that
// no other instructions are inserted into the current block and break.
// The break ensures that no other instruction is generated that will be
// inserted regardless of there is no insertion point and crash (e.g.:
// CreateStore, CreateLoad).
if (dynamic_cast<const ResolvedReturnStmt *>(stmt.get())) {
builder.ClearInsertionPoint();
// We exited the current basic block for some reason, so there is
// no need for generating the remaining instructions.
if (!builder.GetInsertBlock())
break;
}
}
}

Expand Down Expand Up @@ -460,7 +467,7 @@ void Codegen::generateFunctionBody(const ResolvedFunctionDecl &functionDecl) {
generateBlock(*functionDecl.body);

if (retBB->hasNPredecessorsOrMore(1)) {
builder.CreateBr(retBB);
breakIntoBB(retBB);
retBB->insertInto(function);
builder.SetInsertPoint(retBB);
}
Expand Down
2 changes: 1 addition & 1 deletion test/codegen/condition_empty_merge.yl
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ fn main(): void {
// CHECK-NEXT: if.true: ; preds = %entry
// CHECK-NEXT: br label %return
// CHECK-NEXT:
// CHECK-NEXT: if.exit: ; preds = <null operand!>, %entry
// CHECK-NEXT: if.exit: ; preds = %entry
// CHECK-NEXT: br label %return
// CHECK-NEXT:
// CHECK-NEXT: return: ; preds = %if.exit, %if.true
Expand Down
4 changes: 2 additions & 2 deletions test/codegen/constexpr.yl
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ fn constant(): number {
// CHECK-NEXT: store double 1.000000e+00, double* %retval, align 8
// CHECK-NEXT: br label %return
// CHECK-NEXT:
// CHECK-NEXT: return: ; preds = <null operand!>, %entry
// CHECK-NEXT: return: ; preds = %entry
// CHECK-NEXT: %0 = load double, double* %retval, align 8
// CHECK-NEXT: ret double %0
// CHECK-NEXT: }
Expand All @@ -28,7 +28,7 @@ fn constant2(): number {
// CHECK-NEXT: store double 0.000000e+00, double* %retval, align 8
// CHECK-NEXT: br label %return
// CHECK-NEXT:
// CHECK-NEXT: return: ; preds = <null operand!>, %entry
// CHECK-NEXT: return: ; preds = %entry
// CHECK-NEXT: %0 = load double, double* %retval, align 8
// CHECK-NEXT: ret double %0
// CHECK-NEXT: }
Expand Down
2 changes: 1 addition & 1 deletion test/codegen/exercise/immutable_parameters.yl
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ fn foo(s: S, y: number): number {
// CHECK-NEXT: store double %3, double* %retval, align 8
// CHECK-NEXT: br label %return
// CHECK-NEXT:
// CHECK-NEXT: return: ; preds = <null operand!>, %entry
// CHECK-NEXT: return: ; preds = %entry
// CHECK-NEXT: %4 = load double, double* %retval, align 8
// CHECK-NEXT: ret double %4
// CHECK-NEXT: }
Expand Down
4 changes: 2 additions & 2 deletions test/codegen/exercise/return_struct.yl
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ fn foo(var x: number): Small {
// CHECK-NEXT: br label %return

// CHECK-NEXT:
// CHECK-NEXT: return: ; preds = <null operand!>, %entry
// CHECK-NEXT: return: ; preds = %entry
// CHECK-NEXT: ret void
// CHECK-NEXT: }

Expand Down Expand Up @@ -74,7 +74,7 @@ fn bar(): S {

// CHECK-NEXT: br label %return
// CHECK-NEXT:
// CHECK-NEXT: return: ; preds = <null operand!>, %entry
// CHECK-NEXT: return: ; preds = %entry
// CHECK-NEXT: ret void
// CHECK-NEXT: }

Expand Down
2 changes: 1 addition & 1 deletion test/codegen/exercise/struct_parameter.yl
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ fn bar(var s: S): S {
// CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %0, i8* align 8 %1, i64 16, i1 false)
// CHECK-NEXT: br label %return
// CHECK-NEXT:
// CHECK-NEXT: return: ; preds = <null operand!>, %entry
// CHECK-NEXT: return: ; preds = %entry
// CHECK-NEXT: ret void
// CHECK-NEXT: }

Expand Down
2 changes: 1 addition & 1 deletion test/codegen/exercise/structs_generated_first.yl
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ fn foo(s: S): S2 {

// CHECK-NEXT: br label %return
// CHECK-NEXT:
// CHECK-NEXT: return: ; preds = <null operand!>, %entry
// CHECK-NEXT: return: ; preds = %entry
// CHECK-NEXT: ret void
// CHECK-NEXT: }

Expand Down
2 changes: 1 addition & 1 deletion test/codegen/multiple_return.yl
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ fn main(): void {
// CHECK-NEXT: entry:
// CHECK-NEXT: br label %return
// CHECK-NEXT:
// CHECK-NEXT: return: ; preds = <null operand!>, %entry
// CHECK-NEXT: return: ; preds = %entry
// CHECK-NEXT: ret void
// CHECK-NEXT: }
6 changes: 3 additions & 3 deletions test/codegen/multiple_return_if.yl
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,14 @@ fn foo(var x: number): number {
// CHECK-NEXT: store double 1.000000e+01, double* %retval, align 8
// CHECK-NEXT: br label %return
// CHECK-NEXT:
// CHECK-NEXT: if.exit: ; preds = <null operand!>, %if.false
// CHECK-NEXT: if.exit: ; preds = %if.false
// CHECK-NEXT: br label %if.exit5
// CHECK-NEXT:
// CHECK-NEXT: if.exit5: ; preds = %if.exit, <null operand!>
// CHECK-NEXT: if.exit5: ; preds = %if.exit
// CHECK-NEXT: store double 5.200000e+00, double* %retval, align 8
// CHECK-NEXT: br label %return
// CHECK-NEXT:
// CHECK-NEXT: return: ; preds = <null operand!>, %if.exit5, %if.true4, %if.true
// CHECK-NEXT: return: ; preds = %if.exit5, %if.true4, %if.true
// CHECK-NEXT: %4 = load double, double* %retval, align 8
// CHECK-NEXT: ret double %4
// CHECK-NEXT: }
Expand Down
4 changes: 2 additions & 2 deletions test/codegen/multiple_return_while.yl
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@ fn foo(var x: number): number {
// CHECK-NEXT: store double 3.000000e+00, double* %retval, align 8
// CHECK-NEXT: br label %return
// CHECK-NEXT:
// CHECK-NEXT: if.exit: ; preds = <null operand!>, %while.body
// CHECK-NEXT: if.exit: ; preds = %while.body
// CHECK-NEXT: store double 5.000000e+00, double* %retval, align 8
// CHECK-NEXT: br label %return
// CHECK-NEXT:
// CHECK-NEXT: return: ; preds = <null operand!>, %while.exit, %if.exit, %if.true
// CHECK-NEXT: return: ; preds = %while.exit, %if.exit, %if.true
// CHECK-NEXT: %7 = load double, double* %retval, align 8
// CHECK-NEXT: ret double %7

Expand Down
10 changes: 5 additions & 5 deletions test/codegen/return.yl
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ fn noInsertPoint(): void {
// CHECK-NEXT: entry:
// CHECK-NEXT: br label %return
// CHECK-NEXT:
// CHECK-NEXT: return: ; preds = <null operand!>, %entry
// CHECK-NEXT: return: ; preds = %entry
// CHECK-NEXT: ret void
// CHECK-NEXT: }

Expand All @@ -25,7 +25,7 @@ fn insertPointEmptyBlock(): void {
// CHECK-NEXT: if.true: ; preds = %entry
// CHECK-NEXT: br label %return
// CHECK-NEXT:
// CHECK-NEXT: if.exit: ; preds = <null operand!>, %entry
// CHECK-NEXT: if.exit: ; preds = %entry
// CHECK-NEXT: br label %return
// CHECK-NEXT:
// CHECK-NEXT: return: ; preds = %if.exit, %if.true
Expand All @@ -41,7 +41,7 @@ fn insertPointEmptyBlock2(): void {
// CHECK-NEXT: entry:
// CHECK-NEXT: br label %while.cond
// CHECK-NEXT:
// CHECK-NEXT: while.cond: ; preds = <null operand!>, %entry
// CHECK-NEXT: while.cond: ; preds = %entry
// CHECK-NEXT: br i1 true, label %while.body, label %while.exit
// CHECK-NEXT:
// CHECK-NEXT: while.body: ; preds = %while.cond
Expand Down Expand Up @@ -69,7 +69,7 @@ fn insertPointNonEmptyBlock(): void {
// CHECK-NEXT: if.true: ; preds = %entry
// CHECK-NEXT: br label %return
// CHECK-NEXT:
// CHECK-NEXT: if.exit: ; preds = <null operand!>, %entry
// CHECK-NEXT: if.exit: ; preds = %entry
// CHECK-NEXT: store double 1.000000e+00, double* %x, align 8
// CHECK-NEXT: br label %return
// CHECK-NEXT:
Expand All @@ -89,7 +89,7 @@ fn insertPointNonEmptyBlock2(): void {
// CHECK-NEXT: %x = alloca double, align 8
// CHECK-NEXT: br label %while.cond
// CHECK-NEXT:
// CHECK-NEXT: while.cond: ; preds = <null operand!>, %entry
// CHECK-NEXT: while.cond: ; preds = %entry
// CHECK-NEXT: br i1 true, label %while.body, label %while.exit
// CHECK-NEXT:
// CHECK-NEXT: while.body: ; preds = %while.cond
Expand Down
2 changes: 1 addition & 1 deletion test/codegen/while_empty_exit.yl
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ fn foo(var x: number): void {
// CHECK-NEXT: store double %x, double* %x1, align 8
// CHECK-NEXT: br label %while.cond
// CHECK-NEXT:
// CHECK-NEXT: while.cond: ; preds = <null operand!>, %entry
// CHECK-NEXT: while.cond: ; preds = %entry
// CHECK-NEXT: %0 = load double, double* %x1, align 8
// CHECK-NEXT: %1 = fcmp ogt double %0, 1.000000e+00
// CHECK-NEXT: %to.double = uitofp i1 %1 to double
Expand Down