gallivm: Ensure all allocas are in the first block.

Refactor the code to make this easier.
This commit is contained in:
José Fonseca 2010-04-27 13:20:12 +01:00
parent 96df6064b5
commit a18c210a95
6 changed files with 97 additions and 41 deletions

View File

@ -792,3 +792,78 @@ lp_build_endif(struct lp_build_if_state *ctx)
/* Resume building code at end of the ifthen->merge_block */
LLVMPositionBuilderAtEnd(ctx->builder, ifthen->merge_block);
}
/**
* Allocate a scalar (or vector) variable.
*
* Although not strictly part of control flow, control flow has deep impact in
* how variables should be allocated.
*
* The mem2reg optimization pass is the recommended way to dealing with mutable
* variables, and SSA. It looks for allocas and if it can handle them, it
* promotes them, but only looks for alloca instructions in the entry block of
* the function. Being in the entry block guarantees that the alloca is only
* executed once, which makes analysis simpler.
*
* See also:
* - http://www.llvm.org/docs/tutorial/OCamlLangImpl7.html#memory
*/
LLVMValueRef
lp_build_alloca(LLVMBuilderRef builder,
LLVMTypeRef type,
const char *name)
{
LLVMBasicBlockRef current_block = LLVMGetInsertBlock(builder);
LLVMValueRef function = LLVMGetBasicBlockParent(current_block);
LLVMBasicBlockRef first_block = LLVMGetEntryBasicBlock(function);
LLVMValueRef first_instr = LLVMGetFirstInstruction(first_block);
LLVMBuilderRef first_builder = LLVMCreateBuilder();
LLVMValueRef res;
LLVMPositionBuilderAtEnd(first_builder, first_block);
LLVMPositionBuilderBefore(first_builder, first_instr);
res = LLVMBuildAlloca(first_builder, type, name);
LLVMDisposeBuilder(first_builder);
return res;
}
/**
* Allocate an array of scalars/vectors.
*
* mem2reg pass is not capable of promoting structs or arrays to registers, but
* we still put it in the first block anyway as failure to put allocas in the
* first block may prevent the X86 backend from successfully align the stack as
* required.
*
* Also the scalarrepl pass is supossedly more powerful and can promote
* arrays in many cases.
*
* See also:
* - http://www.llvm.org/docs/tutorial/OCamlLangImpl7.html#memory
*/
LLVMValueRef
lp_build_array_alloca(LLVMBuilderRef builder,
LLVMTypeRef type,
LLVMValueRef count,
const char *name)
{
LLVMBasicBlockRef current_block = LLVMGetInsertBlock(builder);
LLVMValueRef function = LLVMGetBasicBlockParent(current_block);
LLVMBasicBlockRef first_block = LLVMGetEntryBasicBlock(function);
LLVMValueRef first_instr = LLVMGetFirstInstruction(first_block);
LLVMBuilderRef first_builder = LLVMCreateBuilder();
LLVMValueRef res;
LLVMPositionBuilderBefore(first_builder, first_instr);
res = LLVMBuildArrayAlloca(first_builder, type, count, name);
LLVMDisposeBuilder(first_builder);
return res;
}

View File

@ -156,5 +156,15 @@ lp_build_endif(struct lp_build_if_state *ctx);
LLVMBasicBlockRef
lp_build_insert_new_block(LLVMBuilderRef builder, const char *name);
LLVMValueRef
lp_build_alloca(LLVMBuilderRef builder,
LLVMTypeRef type,
const char *name);
LLVMValueRef
lp_build_array_alloca(LLVMBuilderRef builder,
LLVMTypeRef type,
LLVMValueRef count,
const char *name);
#endif /* !LP_BLD_FLOW_H */

View File

@ -40,6 +40,7 @@
#include "lp_bld_init.h"
#include "lp_bld_type.h"
#include "lp_bld_flow.h"
#include "lp_bld_format.h"
@ -370,11 +371,7 @@ lp_build_fetch_rgba_aos(LLVMBuilderRef builder,
LLVMAddGlobalMapping(lp_build_engine, function, format_desc->fetch_rgba_float);
}
/*
* XXX: this should better go to the first block in the function
*/
tmp = LLVMBuildAlloca(builder, LLVMVectorType(LLVMFloatType(), 4), "");
tmp = lp_build_alloca(builder, LLVMVectorType(LLVMFloatType(), 4), "");
/*
* Invoke format_desc->fetch_rgba_float() for each pixel and insert the result

View File

@ -472,18 +472,6 @@ lp_build_select_aos(struct lp_build_context *bld,
}
}
LLVMValueRef
lp_build_alloca(struct lp_build_context *bld)
{
const struct lp_type type = bld->type;
if (type.length > 1) { /*vector*/
return LLVMBuildAlloca(bld->builder, lp_build_vec_type(type), "");
} else { /*scalar*/
return LLVMBuildAlloca(bld->builder, lp_build_elem_type(type), "");
}
}
/** Return (a & ~b) */
LLVMValueRef

View File

@ -76,9 +76,6 @@ lp_build_select_aos(struct lp_build_context *bld,
LLVMValueRef b,
const boolean cond[4]);
LLVMValueRef
lp_build_alloca(struct lp_build_context *bld);
LLVMValueRef
lp_build_andc(struct lp_build_context *bld, LLVMValueRef a, LLVMValueRef b);

View File

@ -744,22 +744,11 @@ emit_declaration(
struct lp_build_tgsi_soa_context *bld,
const struct tgsi_full_declaration *decl)
{
LLVMTypeRef vec_type = lp_build_vec_type(bld->base.type);
unsigned first = decl->Range.First;
unsigned last = decl->Range.Last;
unsigned idx, i;
LLVMBasicBlockRef current_block =
LLVMGetInsertBlock(bld->base.builder);
LLVMBasicBlockRef first_block =
LLVMGetEntryBasicBlock(
LLVMGetBasicBlockParent(current_block));
LLVMValueRef first_inst =
LLVMGetFirstInstruction(first_block);
/* we want alloca's to be the first instruction
* in the function so we need to rewind the builder
* to the very beginning */
LLVMPositionBuilderBefore(bld->base.builder,
first_inst);
for (idx = first; idx <= last; ++idx) {
switch (decl->Declaration.File) {
@ -767,23 +756,25 @@ emit_declaration(
if (bld->has_indirect_addressing) {
LLVMValueRef val = LLVMConstInt(LLVMInt32Type(),
last*4 + 4, 0);
bld->temps_array = LLVMBuildArrayAlloca(bld->base.builder,
lp_build_vec_type(bld->base.type),
val, "");
bld->temps_array = lp_build_array_alloca(bld->base.builder,
vec_type, val, "");
} else {
for (i = 0; i < NUM_CHANNELS; i++)
bld->temps[idx][i] = lp_build_alloca(&bld->base);
bld->temps[idx][i] = lp_build_alloca(bld->base.builder,
vec_type, "");
}
break;
case TGSI_FILE_OUTPUT:
for (i = 0; i < NUM_CHANNELS; i++)
bld->outputs[idx][i] = lp_build_alloca(&bld->base);
bld->outputs[idx][i] = lp_build_alloca(bld->base.builder,
vec_type, "");
break;
case TGSI_FILE_ADDRESS:
for (i = 0; i < NUM_CHANNELS; i++)
bld->addr[idx][i] = lp_build_alloca(&bld->base);
bld->addr[idx][i] = lp_build_alloca(bld->base.builder,
vec_type, "");
break;
default:
@ -792,8 +783,6 @@ emit_declaration(
}
}
LLVMPositionBuilderAtEnd(bld->base.builder,
current_block);
return TRUE;
}