Beispiel #1
0
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;
}
Beispiel #2
0
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);
  }
}
Beispiel #3
0
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;
}
Beispiel #4
0
// 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;
}