LLVMValueRef gen_switch(struct node *ast) { LLVMValueRef func, switch_; LLVMBasicBlockRef this_block, switch_first_block, switch_last_block, end_block; int i; this_block = LLVMGetInsertBlock(builder); func = LLVMGetBasicBlockParent(this_block); switch_first_block = LLVMAppendBasicBlock(func, ""); LLVMPositionBuilderAtEnd(builder, switch_first_block); case_count = 0; codegen(ast->two); switch_last_block = LLVMGetLastBasicBlock(func); end_block = LLVMAppendBasicBlock(func, ""); LLVMPositionBuilderAtEnd(builder, switch_last_block); LLVMBuildBr(builder, end_block); LLVMPositionBuilderAtEnd(builder, this_block); switch_ = LLVMBuildSwitch(builder, codegen(ast->one), end_block, case_count); for (i = 0; i < case_count; i++) LLVMAddCase(switch_, case_vals[i], case_blocks[i]); LLVMPositionBuilderAtEnd(builder, end_block); return NULL; }
void Build::visit_select(ast::Select& x) { // Get the current LLVM block and function auto current_block = LLVMGetInsertBlock(_ctx.irb); auto current_fn = LLVMGetBasicBlockParent(current_block); std::vector<LLVMBasicBlockRef> blocks; std::vector<LLVMValueRef> values; std::vector<LLVMBasicBlockRef> value_blocks; // Resolve the type of us (in full; only used if we have a value) auto type = Resolve(_scope).run(x); // A Select expression has a value IIF it has an else and // each of its branches have a value bool has_value = !!type; auto do_select_branch = [&](ast::Block& block) -> bool { // Build the block auto value = Build(_ctx, _scope).run_scalar(block); auto iblock = LLVMGetInsertBlock(_ctx.irb); if (has_value && value && !value->type.is<code::TypeNone>()) { // Cast the value to the type analyzed result value = util::cast(_ctx, value, block, type, false); if (!value) return false; // Append to the value chain values.push_back(value->get_value(_ctx)); value_blocks.push_back(iblock); } else if (!LLVMGetBasicBlockTerminator(iblock)) { // This block wasn't terminated and it has no value // We no longer have a value has_value = false; } // Append to the block chain blocks.push_back(iblock); return true; }; // Iterate through each branch and build its contained block .. for (auto& br : x.branches) { // Build the condition expression auto cond = Build(_ctx, _scope).run_scalar(*br->condition); if (!cond) return; // Create the THEN and NEXT LLVM blocks auto then_block = LLVMAppendBasicBlock(current_fn, "select-then"); auto next_block = LLVMAppendBasicBlock(current_fn, "select-next"); // Build the conditional branch LLVMBuildCondBr(_ctx.irb, cond->get_value(_ctx), then_block, next_block); // Activate the THEN block LLVMPositionBuilderAtEnd(_ctx.irb, then_block); // Process the branch .. if (!do_select_branch(*br->block)) return; // Insert the `next` block after our current block. LLVMMoveBasicBlockAfter(next_block, LLVMGetInsertBlock(_ctx.irb)); // Replace the outer-block with our new "merge" block. LLVMPositionBuilderAtEnd(_ctx.irb, next_block); } // Check for and build the else_block LLVMBasicBlockRef merge_block; if (x.else_block) { // Process the branch .. do_select_branch(*x.else_block); // Create the final "merge" block merge_block = LLVMAppendBasicBlock(current_fn, "select-merge"); } else { // Use the elided "else" block as the "merge" block merge_block = LLVMGetLastBasicBlock(current_fn); } // Iterate through the established branches and have them return to // the "merge" block (if they are not otherwise terminated). unsigned term = 0; for (auto& ib : blocks) { if (!LLVMGetBasicBlockTerminator(ib)) { // Insert the non-conditional branch. LLVMPositionBuilderAtEnd(_ctx.irb, ib); LLVMBuildBr(_ctx.irb, merge_block); } else { term += 1; } } // If all blocks were terminated and there is an ELSE present; // remove the merge block if (term == blocks.size() && x.else_block) { LLVMDeleteBasicBlock(merge_block); } // Re-establish our insertion point. LLVMPositionBuilderAtEnd(_ctx.irb, merge_block); // If we still have a value .. if (has_value && values.size() > 0) { // Make the PHI value auto res = LLVMBuildPhi(_ctx.irb, type->handle(), ""); LLVMAddIncoming(res, values.data(), value_blocks.data(), values.size()); Ref<code::Value> res_value = new code::Value(res, type); _stack.push_front(res_value); } }
LLVMValueRef gen_funcdef(struct node *ast) { LLVMValueRef global, func, retval; LLVMTypeRef func_type, *param_types; LLVMBasicBlockRef body_block, ret_block; int param_count, i; if (hcreate(SYMTAB_SIZE) == 0) generror(">s"); param_count = count_chain(ast->two); param_types = calloc(sizeof(LLVMTypeRef), param_count); if (param_count > 0 && param_types == NULL) generror("out of memory"); for (i = 0; i < param_count; i++) param_types[i] = TYPE_INT; func_type = LLVMFunctionType(TYPE_INT, param_types, param_count, 0); func = LLVMAddFunction(module, ".gfunc", func_type); LLVMSetLinkage(func, LLVMPrivateLinkage); /* TODO: How to specify stack alignment? Should be 16 bytes */ LLVMAddFunctionAttr(func, LLVMStackAlignment); global = find_or_add_global(ast->one->val); LLVMSetInitializer(global, LLVMBuildPtrToInt(builder, func, TYPE_INT, "")); body_block = LLVMAppendBasicBlock(func, ""); ret_block = LLVMAppendBasicBlock(func, ""); LLVMPositionBuilderAtEnd(builder, body_block); retval = LLVMBuildAlloca(builder, TYPE_INT, ""); LLVMBuildStore(builder, CONST(0), retval); symtab_enter(ast->one->val, global); symtab_enter(".return", ret_block); symtab_enter(".retval", retval); label_count = 0; predeclare_labels(ast->three); if (ast->two) codegen(ast->two); codegen(ast->three); LLVMBuildBr(builder, ret_block); /* TODO: Untangle out-of-order blocks */ LLVMPositionBuilderAtEnd(builder, ret_block); LLVMBuildRet(builder, LLVMBuildLoad(builder, retval, "")); LLVMMoveBasicBlockAfter(ret_block, LLVMGetLastBasicBlock(func)); /* TODO: Handle failed verification and print internal compiler error */ LLVMVerifyFunction(func, LLVMPrintMessageAction); hdestroy(); return NULL; }
// Recursively generates LLVM code for the function AST node. // // node - The node to generate an LLVM value for. // module - The compilation unit this node is a part of. // value - A pointer to where the LLVM value should be returned. // // Returns 0 if successful, otherwise returns -1. int qip_ast_function_codegen(qip_ast_node *node, qip_module *module, LLVMValueRef *value) { int rc; LLVMBuilderRef builder = module->compiler->llvm_builder; // Create function prototype. LLVMValueRef func = NULL; rc = qip_ast_function_codegen_prototype(node, module, &func); check(rc == 0, "Unable to generate function prototype"); // Store the current function on the module. qip_scope *scope = qip_scope_create_function(func); check_mem(scope); rc = qip_module_push_scope(module, scope); check(rc == 0, "Unable to add function scope"); // Grab the External metadata node if there is one. qip_ast_node *external_metadata_node = NULL; rc = qip_ast_function_get_external_metadata_node(node, &external_metadata_node); check(rc == 0, "Unable to retrieve external metadata node"); // Generate basic block for body. LLVMBasicBlockRef block = LLVMAppendBasicBlock(scope->llvm_function, ""); // Generate function arguments. LLVMPositionBuilderAtEnd(builder, block); rc = qip_ast_function_codegen_args(node, module); check(rc == 0, "Unable to codegen function arguments"); // If this function is marked as external then dynamically generate the // code to call the function and return the value. if(external_metadata_node != NULL) { rc = qip_ast_function_generate_external_call(node, module, block); check(rc == 0, "Unable to generate call to external function"); } // Otherwise generate the body if it exists. else if(node->function.body != NULL) { rc = qip_ast_block_codegen_with_block(node->function.body, module, block); check(rc == 0, "Unable to generate function body statements"); // If this is a void return type and there is no explicit return then // add one before the end. if(qip_ast_type_ref_is_void(node->function.return_type)) { if(node->function.body->block.expr_count > 0 && node->function.body->block.exprs[node->function.body->block.expr_count-1]->type != QIP_AST_TYPE_FRETURN) { LLVMBuildRetVoid(builder); } } } // If there's no body or it's not external then we have a problem. else { sentinel("Function must be external or have a body"); } // Dump before verification. //LLVMDumpValue(func); // Verify function. rc = LLVMVerifyFunction(func, LLVMPrintMessageAction); check(rc != 1, "Invalid function"); // Unset the current function. rc = qip_module_pop_scope(module); check(rc == 0, "Unable to remove function scope"); if(scope->llvm_last_alloca != NULL) { LLVMInstructionEraseFromParent(scope->llvm_last_alloca); scope->llvm_last_alloca = NULL; } // Reset the builder position at the end of the new function scope if // one still exists. qip_scope *new_scope = NULL; rc = qip_module_get_current_function_scope(module, &new_scope); check(rc == 0, "Unable to retrieve new function scope"); if(new_scope != NULL) { LLVMPositionBuilderAtEnd(builder, LLVMGetLastBasicBlock(new_scope->llvm_function)); } // Return function as a value. *value = func; return 0; error: //if(func) LLVMDeleteFunction(func); *value = NULL; return -1; }