fix if statement emitting

- don't emit br instructions (or any other) if branch emits ret
 - remove phi node (ifs are statements, not exprs)

 - emit to testfile (even if ir is broken)
This commit is contained in:
Luna 2019-09-24 18:49:35 -03:00
parent c1d6939c43
commit 9e80ad4c23
2 changed files with 51 additions and 17 deletions

View file

@ -114,11 +114,10 @@ pub const Codegen = struct {
var insert = llvm.LLVMGetInsertBlock(builder); var insert = llvm.LLVMGetInsertBlock(builder);
var function = llvm.LLVMGetBasicBlockParent(insert); var function = llvm.LLVMGetBasicBlockParent(insert);
var global_ctx = llvm.LLVMGetGlobalContext();
var then_bb = llvm.LLVMAppendBasicBlock(function, c"then"); var then_bb = llvm.LLVMAppendBasicBlock(function, c"then");
var else_bb = llvm.LLVMCreateBasicBlockInContext(global_ctx, c"else"); var else_bb = llvm.LLVMAppendBasicBlock(function, c"else");
var merge_bb = llvm.LLVMCreateBasicBlockInContext(global_ctx, c"ifcont"); var merge_bb = llvm.LLVMAppendBasicBlock(function, c"ifcont");
var condbr = llvm.LLVMBuildCondBr(builder, icmp, then_bb, else_bb); var condbr = llvm.LLVMBuildCondBr(builder, icmp, then_bb, else_bb);
@ -126,11 +125,27 @@ pub const Codegen = struct {
// roughly translating to kaleidoscope's // roughly translating to kaleidoscope's
// 'Value *ThenV = Then->codegen();' // 'Value *ThenV = Then->codegen();'
var then_rets = false;
var else_rets = false;
for (ifstmt.then_branch.toSlice()) |then_stmt| { for (ifstmt.then_branch.toSlice()) |then_stmt| {
try self.emitStmt(builder, &then_stmt);
// keep emitting until branch has ret
if (!then_rets)
try self.emitStmt(builder, &then_stmt);
switch (then_stmt) {
.Return => then_rets = true,
else => {},
}
} }
_ = llvm.LLVMBuildBr(builder, merge_bb); // only build the br instruction if we didn't ret, because
// there can't be any instruction after a terminator
// same applies for the else branch
if (!then_rets)
_ = llvm.LLVMBuildBr(builder, merge_bb);
then_bb = llvm.LLVMGetInsertBlock(builder); then_bb = llvm.LLVMGetInsertBlock(builder);
llvm.LLVMPositionBuilderAtEnd(builder, else_bb); llvm.LLVMPositionBuilderAtEnd(builder, else_bb);
@ -139,22 +154,34 @@ pub const Codegen = struct {
// 'Else *ElseV = Else->codegen();' // 'Else *ElseV = Else->codegen();'
if (ifstmt.else_branch) |else_block| { if (ifstmt.else_branch) |else_block| {
for (else_block.toSlice()) |else_stmt| { for (else_block.toSlice()) |else_stmt| {
try self.emitStmt(builder, &else_stmt); // keep emitting until branch has ret
if (!else_rets)
try self.emitStmt(builder, &else_stmt);
switch (else_stmt) {
.Return => else_rets = true,
else => {},
}
} }
} }
_ = llvm.LLVMBuildBr(builder, merge_bb); if (!else_rets)
_ = llvm.LLVMBuildBr(builder, merge_bb);
else_bb = llvm.LLVMGetInsertBlock(builder); else_bb = llvm.LLVMGetInsertBlock(builder);
llvm.LLVMPositionBuilderAtEnd(builder, merge_bb); llvm.LLVMPositionBuilderAtEnd(builder, merge_bb);
var phi = llvm.LLVMBuildPhi(builder, llvm.LLVMVoidType(), c"iftmp"); if (then_rets and else_rets)
_ = llvm.LLVMBuildUnreachable(builder);
var then_bb_val = llvm.LLVMBasicBlockAsValue(then_bb); // phis aren't needed since our ifs arent expressions
var else_bb_val = llvm.LLVMBasicBlockAsValue(else_bb);
llvm.LLVMAddIncoming(phi, &then_bb_val, &then_bb, 1); //var phi = llvm.LLVMBuildPhi(builder, llvm.LLVMVoidType(), c"iftmp");
llvm.LLVMAddIncoming(phi, &else_bb_val, &else_bb, 1); //var then_bb_val = llvm.LLVMBasicBlockAsValue(then_bb);
//var else_bb_val = llvm.LLVMBasicBlockAsValue(else_bb);
//llvm.LLVMAddIncoming(phi, &then_bb_val, &then_bb, 1);
//llvm.LLVMAddIncoming(phi, &else_bb_val, &else_bb, 1);
}, },
else => { else => {
@ -250,17 +277,23 @@ pub const Codegen = struct {
var err: ?[*]u8 = null; var err: ?[*]u8 = null;
defer llvm.LLVMDisposeMessage(err); defer llvm.LLVMDisposeMessage(err);
_ = llvm.LLVMVerifyModule( if (llvm.LLVMPrintModuleToFile(mod, c"testfile", &err) != 0) {
mod, std.debug.warn("error printing module to file: {}\n", sliceify(err));
llvm.LLVMVerifierFailureAction.LLVMAbortProcessAction, return CompileError.LLVMError;
&err, }
);
if (llvm.LLVMWriteBitcodeToFile(mod, c"awoo.bc") != 0) { if (llvm.LLVMWriteBitcodeToFile(mod, c"awoo.bc") != 0) {
std.debug.warn("error writing bitcode to file: {}\n", sliceify(err)); std.debug.warn("error writing bitcode to file: {}\n", sliceify(err));
return CompileError.LLVMError; return CompileError.LLVMError;
} }
std.debug.warn("cgen: verify llvm module\n");
_ = llvm.LLVMVerifyModule(
mod,
llvm.LLVMVerifierFailureAction.LLVMAbortProcessAction,
&err,
);
llvm.LLVMInitializeAllTargetInfos(); llvm.LLVMInitializeAllTargetInfos();
llvm.LLVMInitializeAllTargets(); llvm.LLVMInitializeAllTargets();
llvm.LLVMInitializeAllTargetMCs(); llvm.LLVMInitializeAllTargetMCs();

View file

@ -798,6 +798,7 @@ pub const Parser = struct {
fn parseReturn(self: *@This()) !*Stmt { fn parseReturn(self: *@This()) !*Stmt {
const tok = try self.consumeSingle(.Return); const tok = try self.consumeSingle(.Return);
// TODO if (self.check(.Semicolon)) insert a void literal?
const expr = try self.parseExpr(); const expr = try self.parseExpr();
return try Stmt.mkReturn(self.allocator, tok, expr); return try Stmt.mkReturn(self.allocator, tok, expr);
} }