Commit 08ca3fc0 authored by Doug Nazar's avatar Doug Nazar Committed by Sebastian Dröge

powerpc: Pre-load long constants & invariants

PowerPC doesn't have an easy way to load a long constant into a
vector register so we emit the value into the code and then load it.

This moves those values to after the epilogue and then loads them
before starting the outer loop.
parent f9dbb051
......@@ -29,6 +29,7 @@ struct _OrcConstant {
unsigned int full_value[4];
int use_count;
int is_long;
int label;
};
......
......@@ -441,11 +441,22 @@ orc_powerpc_flush_cache (OrcCode *code)
#endif
}
static void
void
powerpc_emit_load_address (OrcCompiler* compiler, int regd, int rega, int imm)
{
if (compiler->is_64bit) {
powerpc_emit_ld (compiler, regd, rega, imm);
} else {
powerpc_emit_lwz (compiler, regd, rega, imm);
}
}
void
powerpc_load_constant (OrcCompiler *p, int i, int reg)
{
int j;
int value = p->constants[i].value;
int greg = p->gp_tmpreg;
switch (p->constants[i].type) {
case ORC_CONST_ZERO:
......@@ -492,6 +503,7 @@ powerpc_load_constant (OrcCompiler *p, int i, int reg)
value &= 0xff;
value |= (value<<8);
value |= (value<<16);
value |= (value<<24);
for(j=0;j<4;j++){
p->constants[i].full_value[j] = value;
}
......@@ -512,31 +524,39 @@ powerpc_load_constant (OrcCompiler *p, int i, int reg)
break;
}
powerpc_load_long_constant (p, reg,
p->constants[i].full_value[0],
p->constants[i].full_value[1],
p->constants[i].full_value[2],
p->constants[i].full_value[3]);
}
p->constants[i].is_long = TRUE;
if (p->constants[i].label == 0) {
p->constants[i].label = orc_compiler_label_new(p);
}
void
powerpc_load_long_constant (OrcCompiler *p, int reg, orc_uint32 a,
orc_uint32 b, orc_uint32 c, orc_uint32 d)
{
int label_skip, label_data;
int greg = p->gp_tmpreg;
powerpc_emit_load_address (p, greg, POWERPC_R3,
(int)ORC_STRUCT_OFFSET(OrcExecutor, arrays[ORC_VAR_A2]));
powerpc_emit_load_address (p, greg, greg,
(int)ORC_STRUCT_OFFSET(OrcCode, exec));
label_skip = orc_compiler_label_new (p);
label_data = orc_compiler_label_new (p);
powerpc_add_fixup (p, 1, p->codeptr, p->constants[i].label);
{
unsigned int insn;
powerpc_emit_b (p, label_skip);
ORC_ASM_CODE(p," addi %s, %s, %db - %s\n",
powerpc_get_regname(greg),
powerpc_get_regname(greg), p->constants[i].label, p->program->name);
insn = (14<<26) | (powerpc_regnum (greg)<<21) | (powerpc_regnum (greg)<<16);
insn |= 0;
while ((p->codeptr - p->code) & 0xf) {
ORC_ASM_CODE(p," .long 0x00000000\n");
powerpc_emit (p, 0x00000000);
powerpc_emit (p, insn);
}
powerpc_emit_label (p, label_data);
ORC_ASM_CODE(p," lvx %s, 0, %s\n",
powerpc_get_regname(reg),
powerpc_get_regname(greg));
powerpc_emit_X (p, 0x7c0000ce, reg, 0, greg);
}
static void
powerpc_emit_long_value(OrcCompiler* p, orc_uint32 a, orc_uint32 b,
orc_uint32 c, orc_uint32 d)
{
if (IS_POWERPC_BE(p)) {
ORC_ASM_CODE(p," .long 0x%08x\n", a);
powerpc_emit (p, a);
......@@ -556,44 +576,44 @@ powerpc_load_long_constant (OrcCompiler *p, int reg, orc_uint32 a,
ORC_ASM_CODE(p," .long 0x%08x\n", a);
powerpc_emit (p, a);
}
}
powerpc_emit_label (p, label_skip);
if (p->is_64bit) {
powerpc_emit_ld (p,
greg,
POWERPC_R3,
(int)ORC_STRUCT_OFFSET(OrcExecutor, arrays[ORC_VAR_A2]));
powerpc_emit_ld (p,
greg, greg,
(int)ORC_STRUCT_OFFSET(OrcCode, exec));
} else {
powerpc_emit_lwz (p,
greg,
POWERPC_R3,
(int)ORC_STRUCT_OFFSET(OrcExecutor, arrays[ORC_VAR_A2]));
powerpc_emit_lwz (p,
greg, greg,
(int)ORC_STRUCT_OFFSET(OrcCode, exec));
}
powerpc_add_fixup (p, 1, p->codeptr, label_data);
{
unsigned int insn;
ORC_ASM_CODE(p," addi %s, %s, %db - %s\n",
powerpc_get_regname(greg),
powerpc_get_regname(greg), label_data, p->program->name);
insn = (14<<26) | (powerpc_regnum (greg)<<21) | (powerpc_regnum (greg)<<16);
insn |= 0;
powerpc_emit (p, insn);
void
powerpc_emit_full_constants(OrcCompiler* p)
{
int i;
int aligned = FALSE;
for (i = 0; i < p->n_constants; i++) {
if (p->constants[i].is_long == TRUE && p->constants[i].label) {
if (!aligned) {
while ((p->codeptr - p->code) & 0xf) {
ORC_ASM_CODE(p, " .long 0x00000000\n");
powerpc_emit(p, 0x00000000);
}
aligned = TRUE;
}
powerpc_emit_label(p, p->constants[i].label);
powerpc_emit_long_value(p,
p->constants[i].full_value[0], p->constants[i].full_value[1],
p->constants[i].full_value[2], p->constants[i].full_value[3]);
}
}
}
ORC_ASM_CODE(p," lvx %s, 0, %s\n",
powerpc_get_regname(reg),
powerpc_get_regname(greg));
powerpc_emit_X (p, 0x7c0000ce, reg, 0, greg);
void
powerpc_load_long_constant (OrcCompiler *p, int reg, orc_uint32 value0,
orc_uint32 value1, orc_uint32 value2, orc_uint32 value3)
{
int i = p->n_constants++;
p->constants[i].type = ORC_CONST_FULL;
p->constants[i].full_value[0] = value0;
p->constants[i].full_value[1] = value1;
p->constants[i].full_value[2] = value2;
p->constants[i].full_value[3] = value3;
p->constants[i].alloc_reg = -1;
powerpc_load_constant (p, i, reg);
}
int
......@@ -605,7 +625,7 @@ powerpc_get_constant (OrcCompiler *p, int type, int value)
for(i=0;i<p->n_constants;i++){
if (p->constants[i].type == type &&
p->constants[i].value == value) {
if (p->constants[i].alloc_reg != 0) {
if (p->constants[i].alloc_reg > 0) {
return p->constants[i].alloc_reg;
}
break;
......@@ -631,15 +651,16 @@ powerpc_get_constant_full (OrcCompiler *p, int value0, int value1,
int i;
for(i=0;i<p->n_constants;i++){
#if 0
if (p->constants[i].type == type &&
p->constants[i].value == value) {
if (p->constants[i].alloc_reg != 0) {
if (p->constants[i].type == ORC_CONST_FULL &&
p->constants[i].full_value[0] == value0 &&
p->constants[i].full_value[1] == value1 &&
p->constants[i].full_value[2] == value2 &&
p->constants[i].full_value[3] == value3) {
if (p->constants[i].alloc_reg > 0) {
return p->constants[i].alloc_reg;
}
break;
}
#endif
}
if (i == p->n_constants) {
p->n_constants++;
......
......@@ -136,6 +136,9 @@ void powerpc_emit_VX_4 (OrcCompiler *p, const char *name, unsigned int insn, int
int powerpc_get_constant (OrcCompiler *p, int type, int value);
int powerpc_get_constant_full (OrcCompiler *p, int value0, int value1, int value2, int value3);
void powerpc_load_long_constant (OrcCompiler *p, int reg, orc_uint32 a, orc_uint32 b, orc_uint32 c, orc_uint32 d);
void powerpc_emit_full_constants (OrcCompiler* p);
void powerpc_emit_load_address (OrcCompiler* compiler, int regd, int rega, int imm);
void powerpc_load_constant (OrcCompiler* p, int i, int reg);
/* instructions */
#define powerpc_emit_vand(p,a,b,c) powerpc_emit_VX_2 (p, "vand", 0x10000404, a, b, c)
......
......@@ -142,6 +142,47 @@ orc_compiler_powerpc_init (OrcCompiler *compiler)
compiler->load_params = TRUE;
}
static void
powerpc_load_constants_outer (OrcCompiler *compiler)
{
int i;
for(i=0;i<ORC_N_COMPILER_VARIABLES;i++){
if (compiler->vars[i].name == NULL) continue;
switch (compiler->vars[i].vartype) {
case ORC_VAR_TYPE_CONST:
break;
case ORC_VAR_TYPE_PARAM:
break;
case ORC_VAR_TYPE_SRC:
case ORC_VAR_TYPE_DEST:
break;
case ORC_VAR_TYPE_ACCUMULATOR:
powerpc_emit_vxor(compiler, compiler->vars[i].alloc,
compiler->vars[i].alloc, compiler->vars[i].alloc);
break;
case ORC_VAR_TYPE_TEMP:
break;
default:
orc_compiler_error(compiler,"bad vartype");
break;
}
}
orc_compiler_emit_invariants (compiler);
for(i=0;i<compiler->n_constants;i++) {
if (compiler->constants[i].is_long &&
!compiler->constants[i].alloc_reg) {
compiler->constants[i].alloc_reg =
orc_compiler_get_constant_reg (compiler);
if (compiler->constants[i].alloc_reg > 0) {
powerpc_load_constant (compiler, i,
compiler->constants[i].alloc_reg);
}
}
}
}
static void
powerpc_load_inner_constants (OrcCompiler *compiler)
{
......@@ -153,17 +194,10 @@ powerpc_load_inner_constants (OrcCompiler *compiler)
case ORC_VAR_TYPE_SRC:
case ORC_VAR_TYPE_DEST:
if (compiler->vars[i].ptr_register) {
if (compiler->is_64bit) {
powerpc_emit_ld (compiler,
compiler->vars[i].ptr_register,
POWERPC_R3,
(int)ORC_STRUCT_OFFSET(OrcExecutor, arrays[i]));
} else {
powerpc_emit_lwz (compiler,
compiler->vars[i].ptr_register,
POWERPC_R3,
(int)ORC_STRUCT_OFFSET(OrcExecutor, arrays[i]));
}
powerpc_emit_load_address (compiler,
compiler->vars[i].ptr_register,
POWERPC_R3,
(int)ORC_STRUCT_OFFSET(OrcExecutor, arrays[i]));
} else {
/* FIXME */
ORC_ASM_CODE(compiler,"ERROR");
......@@ -176,14 +210,65 @@ powerpc_load_inner_constants (OrcCompiler *compiler)
}
static void
orc_compiler_powerpc_assemble (OrcCompiler *compiler)
orc_powerpc_emit_loop (OrcCompiler* compiler, int update)
{
int j;
int k;
OrcInstruction *insn;
OrcStaticOpcode *opcode;
/* OrcVariable *args[10]; */
OrcRule *rule;
for(j=0;j<compiler->n_insns;j++){
insn = compiler->insns + j;
opcode = insn->opcode;
compiler->insn_index = j;
if (insn->flags & ORC_INSN_FLAG_INVARIANT) continue;
ORC_ASM_CODE(compiler,"# %d: %s\n", j, insn->opcode->name);
compiler->min_temp_reg = ORC_VEC_REG_BASE;
compiler->insn_shift = compiler->loop_shift;
if (insn->flags & ORC_INSTRUCTION_FLAG_X2) {
compiler->insn_shift += 1;
}
if (insn->flags & ORC_INSTRUCTION_FLAG_X4) {
compiler->insn_shift += 2;
}
rule = insn->rule;
if (rule && rule->emit) {
rule->emit (compiler, rule->emit_user, insn);
} else {
orc_compiler_error (compiler, "no code generation rule for %s",
opcode->name);
}
}
if (update) {
for(k=0;k<ORC_N_COMPILER_VARIABLES;k++){
if (compiler->vars[k].name == NULL) continue;
if (compiler->vars[k].vartype == ORC_VAR_TYPE_SRC ||
compiler->vars[k].vartype == ORC_VAR_TYPE_DEST) {
if (compiler->vars[k].ptr_register) {
powerpc_emit_addi (compiler,
compiler->vars[k].ptr_register,
compiler->vars[k].ptr_register,
compiler->vars[k].size << compiler->loop_shift);
} else {
ORC_ASM_CODE(compiler,"ERROR\n");
}
}
}
}
}
static void
orc_compiler_powerpc_assemble (OrcCompiler *compiler)
{
int k;
int label_outer_loop_start;
int label_loop_start;
int label_leave;
......@@ -193,6 +278,27 @@ orc_compiler_powerpc_assemble (OrcCompiler *compiler)
label_loop_start = orc_compiler_label_new (compiler);
label_leave = orc_compiler_label_new (compiler);
{
int i;
orc_powerpc_emit_loop (compiler, 0);
compiler->codeptr = compiler->code;
free (compiler->asm_code);
compiler->asm_code = NULL;
compiler->asm_code_len = 0;
memset (compiler->labels, 0, sizeof (compiler->labels));
memset (compiler->labels_int, 0, sizeof (compiler->labels_int));
compiler->n_fixups = 0;
compiler->n_output_insns = 0;
for(i=0;i<compiler->n_constants;i++) {
compiler->constants[i].label = 0;
}
}
if (compiler->error) return;
powerpc_emit_prologue (compiler);
if (orc_program_has_float (compiler)) {
......@@ -208,6 +314,8 @@ orc_compiler_powerpc_assemble (OrcCompiler *compiler)
powerpc_emit_VX_b(compiler, "mtvscr", 0x10000644, tmp);
}
powerpc_load_constants_outer (compiler);
if (compiler->program->is_2d) {
powerpc_emit_lwz (compiler, POWERPC_R0, POWERPC_R3,
(int)ORC_STRUCT_OFFSET(OrcExecutorAlt, m));
......@@ -218,18 +326,8 @@ orc_compiler_powerpc_assemble (OrcCompiler *compiler)
(int)ORC_STRUCT_OFFSET(OrcExecutorAlt, m_index));
}
/* powerpc_load_constants (compiler); */
powerpc_load_inner_constants (compiler);
for(k=0;k<4;k++){
OrcVariable *var = &compiler->vars[ORC_VAR_A1 + k];
if (compiler->vars[ORC_VAR_A1 + k].name == NULL) continue;
/* powerpc_emit_VX_2(p, "vxor", 0x100004c4, reg, reg, reg); */
powerpc_emit_vxor (compiler, var->alloc, var->alloc, var->alloc);
}
powerpc_emit_label (compiler, label_outer_loop_start);
powerpc_emit_lwz (compiler, POWERPC_R0, POWERPC_R3,
......@@ -244,85 +342,7 @@ orc_compiler_powerpc_assemble (OrcCompiler *compiler)
powerpc_emit_label (compiler, label_loop_start);
for(j=0;j<compiler->n_insns;j++){
insn = compiler->insns + j;
opcode = insn->opcode;
compiler->insn_index = j;
ORC_ASM_CODE(compiler,"# %d: %s\n", j, insn->opcode->name);
#if 0
/* set up args */
for(k=0;k<opcode->n_src + opcode->n_dest;k++){
args[k] = compiler->vars + insn->args[k];
ORC_ASM_CODE(compiler," %d", args[k]->alloc);
if (args[k]->is_chained) {
ORC_ASM_CODE(compiler," (chained)");
}
}
ORC_ASM_CODE(compiler,"\n");
#endif
for(k=0;k<ORC_STATIC_OPCODE_N_SRC;k++){
OrcVariable *var = compiler->vars + insn->src_args[k];
if (opcode->src_size[k] == 0) continue;
switch (var->vartype) {
case ORC_VAR_TYPE_SRC:
case ORC_VAR_TYPE_DEST:
/* powerpc_emit_load_src (compiler, var); */
break;
case ORC_VAR_TYPE_CONST:
break;
case ORC_VAR_TYPE_TEMP:
break;
default:
break;
}
}
compiler->min_temp_reg = ORC_VEC_REG_BASE;
rule = insn->rule;
if (rule) {
rule->emit (compiler, rule->emit_user, insn);
} else {
ORC_ASM_CODE(compiler,"No rule for: %s\n", opcode->name);
}
for(k=0;k<ORC_STATIC_OPCODE_N_DEST;k++){
OrcVariable *var = compiler->vars + insn->dest_args[k];
if (opcode->dest_size[k] == 0) continue;
switch (var->vartype) {
case ORC_VAR_TYPE_DEST:
/* powerpc_emit_store_dest (compiler, var); */
break;
case ORC_VAR_TYPE_TEMP:
break;
default:
break;
}
}
}
for(k=0;k<ORC_N_COMPILER_VARIABLES;k++){
if (compiler->vars[k].name == NULL) continue;
if (compiler->vars[k].vartype == ORC_VAR_TYPE_SRC ||
compiler->vars[k].vartype == ORC_VAR_TYPE_DEST) {
if (compiler->vars[k].ptr_register) {
powerpc_emit_addi (compiler,
compiler->vars[k].ptr_register,
compiler->vars[k].ptr_register,
compiler->vars[k].size << compiler->loop_shift);
} else {
ORC_ASM_CODE(compiler,"ERROR\n");
}
}
}
orc_powerpc_emit_loop (compiler, 1);
powerpc_emit_bne (compiler, label_loop_start);
......@@ -340,17 +360,10 @@ orc_compiler_powerpc_assemble (OrcCompiler *compiler)
if (compiler->vars[k].vartype == ORC_VAR_TYPE_SRC ||
compiler->vars[k].vartype == ORC_VAR_TYPE_DEST) {
if (compiler->vars[k].ptr_register) {
if (compiler->is_64bit) {
powerpc_emit_ld (compiler,
compiler->vars[k].ptr_register,
POWERPC_R3,
(int)ORC_STRUCT_OFFSET(OrcExecutor, arrays[k]));
} else {
powerpc_emit_lwz (compiler,
compiler->vars[k].ptr_register,
POWERPC_R3,
(int)ORC_STRUCT_OFFSET(OrcExecutor, arrays[k]));
}
powerpc_emit_load_address (compiler,
compiler->vars[k].ptr_register,
POWERPC_R3,
(int)ORC_STRUCT_OFFSET(OrcExecutor, arrays[k]));
powerpc_emit_lwz (compiler,
POWERPC_R0,
POWERPC_R3,
......@@ -437,6 +450,8 @@ orc_compiler_powerpc_assemble (OrcCompiler *compiler)
}
powerpc_emit_epilogue (compiler);
powerpc_emit_full_constants (compiler);
powerpc_do_fixups (compiler);
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment