(op == INSTR_ADDRESS) ||
(op >= INSTR_NOT_F && op <= INSTR_NOT_FNC) ||
(op >= INSTR_AND && op <= INSTR_BITOR) ||
- (op >= INSTR_CALL0 && op <= INSTR_CALL8) );
+ (op >= INSTR_CALL0 && op <= INSTR_CALL8) ||
+ (op >= VINSTR_BITAND_V && op <= VINSTR_CROSS) );
}
static bool ir_function_pass_peephole(ir_function *self)
if (!instr_is_operation(oper->opcode))
continue;
+ /* Don't change semantics of MUL_VF in engines where these may not alias. */
if (OPTS_FLAG(LEGACY_VECTOR_MATHS)) {
if (oper->opcode == INSTR_MUL_VF && oper->_ops[2]->memberof == oper->_ops[1])
continue;
#endif
case INSTR_BITAND:
case INSTR_BITOR:
+ case VINSTR_BITXOR:
#if 0
case INSTR_SUB_S: /* -- offset of string as float */
case INSTR_MUL_IF:
case INSTR_SUB_V:
case INSTR_MUL_VF:
case INSTR_MUL_FV:
+ case VINSTR_BITAND_V:
+ case VINSTR_BITOR_V:
+ case VINSTR_BITXOR_V:
+ case VINSTR_BITAND_VF:
+ case VINSTR_BITOR_VF:
+ case VINSTR_BITXOR_VF:
+ case VINSTR_CROSS:
#if 0
case INSTR_DIV_VF:
case INSTR_MUL_IV:
}
}
- if (instr->opcode == INSTR_MUL_VF)
+ /* These operations need a special case as they can break when using
+ * same source and destination operand otherwise, as the engine may
+ * read the source multiple times. */
+ if (instr->opcode == INSTR_MUL_VF ||
+ instr->opcode == VINSTR_BITAND_VF ||
+ instr->opcode == VINSTR_BITOR_VF ||
+ instr->opcode == VINSTR_BITXOR ||
+ instr->opcode == VINSTR_BITXOR_VF ||
+ instr->opcode == VINSTR_BITXOR_V ||
+ instr->opcode == VINSTR_CROSS)
{
value = instr->_ops[2];
/* the float source will get an additional lifetime */
if (value->memberof && ir_value_life_merge(value->memberof, instr->eid+1))
*changed = true;
}
- else if (instr->opcode == INSTR_MUL_FV || instr->opcode == INSTR_LOAD_V)
+
+ if (instr->opcode == INSTR_MUL_FV ||
+ instr->opcode == INSTR_LOAD_V ||
+ instr->opcode == VINSTR_BITXOR ||
+ instr->opcode == VINSTR_BITXOR_VF ||
+ instr->opcode == VINSTR_BITXOR_V ||
+ instr->opcode == VINSTR_CROSS)
{
value = instr->_ops[1];
/* the float source will get an additional lifetime */
ir_block *onfalse;
size_t stidx;
size_t i;
+ int j;
block->generated = true;
block->code_start = vec_size(code->statements);
stmt.o2.s1 = 0;
stmt.o3.s1 = 0;
if (stmt.o1.s1 != 1)
- code_push_statement(code, &stmt, instr->context.line);
+ code_push_statement(code, &stmt, instr->context);
/* no further instructions can be in this block */
return true;
}
+ if (instr->opcode == VINSTR_BITXOR) {
+ stmt.opcode = INSTR_BITOR;
+ stmt.o1.s1 = ir_value_code_addr(instr->_ops[1]);
+ stmt.o2.s1 = ir_value_code_addr(instr->_ops[2]);
+ stmt.o3.s1 = ir_value_code_addr(instr->_ops[0]);
+ code_push_statement(code, &stmt, instr->context);
+ stmt.opcode = INSTR_BITAND;
+ stmt.o1.s1 = ir_value_code_addr(instr->_ops[1]);
+ stmt.o2.s1 = ir_value_code_addr(instr->_ops[2]);
+ stmt.o3.s1 = ir_value_code_addr(func->owner->vinstr_temp[0]);
+ code_push_statement(code, &stmt, instr->context);
+ stmt.opcode = INSTR_SUB_F;
+ stmt.o1.s1 = ir_value_code_addr(instr->_ops[0]);
+ stmt.o2.s1 = ir_value_code_addr(func->owner->vinstr_temp[0]);
+ stmt.o3.s1 = ir_value_code_addr(instr->_ops[0]);
+ code_push_statement(code, &stmt, instr->context);
+
+ /* instruction generated */
+ continue;
+ }
+
+ if (instr->opcode == VINSTR_BITAND_V) {
+ stmt.opcode = INSTR_BITAND;
+ stmt.o1.s1 = ir_value_code_addr(instr->_ops[1]);
+ stmt.o2.s1 = ir_value_code_addr(instr->_ops[2]);
+ stmt.o3.s1 = ir_value_code_addr(instr->_ops[0]);
+ code_push_statement(code, &stmt, instr->context);
+ ++stmt.o1.s1;
+ ++stmt.o2.s1;
+ ++stmt.o3.s1;
+ code_push_statement(code, &stmt, instr->context);
+ ++stmt.o1.s1;
+ ++stmt.o2.s1;
+ ++stmt.o3.s1;
+ code_push_statement(code, &stmt, instr->context);
+
+ /* instruction generated */
+ continue;
+ }
+
+ if (instr->opcode == VINSTR_BITOR_V) {
+ stmt.opcode = INSTR_BITOR;
+ stmt.o1.s1 = ir_value_code_addr(instr->_ops[1]);
+ stmt.o2.s1 = ir_value_code_addr(instr->_ops[2]);
+ stmt.o3.s1 = ir_value_code_addr(instr->_ops[0]);
+ code_push_statement(code, &stmt, instr->context);
+ ++stmt.o1.s1;
+ ++stmt.o2.s1;
+ ++stmt.o3.s1;
+ code_push_statement(code, &stmt, instr->context);
+ ++stmt.o1.s1;
+ ++stmt.o2.s1;
+ ++stmt.o3.s1;
+ code_push_statement(code, &stmt, instr->context);
+
+ /* instruction generated */
+ continue;
+ }
+
+ if (instr->opcode == VINSTR_BITXOR_V) {
+ for (j = 0; j < 3; ++j) {
+ stmt.opcode = INSTR_BITOR;
+ stmt.o1.s1 = ir_value_code_addr(instr->_ops[1]) + j;
+ stmt.o2.s1 = ir_value_code_addr(instr->_ops[2]) + j;
+ stmt.o3.s1 = ir_value_code_addr(instr->_ops[0]) + j;
+ code_push_statement(code, &stmt, instr->context);
+ stmt.opcode = INSTR_BITAND;
+ stmt.o1.s1 = ir_value_code_addr(instr->_ops[1]) + j;
+ stmt.o2.s1 = ir_value_code_addr(instr->_ops[2]) + j;
+ stmt.o3.s1 = ir_value_code_addr(func->owner->vinstr_temp[0]) + j;
+ code_push_statement(code, &stmt, instr->context);
+ }
+ stmt.opcode = INSTR_SUB_V;
+ stmt.o1.s1 = ir_value_code_addr(instr->_ops[0]);
+ stmt.o2.s1 = ir_value_code_addr(func->owner->vinstr_temp[0]);
+ stmt.o3.s1 = ir_value_code_addr(instr->_ops[0]);
+ code_push_statement(code, &stmt, instr->context);
+
+ /* instruction generated */
+ continue;
+ }
+
+ if (instr->opcode == VINSTR_BITAND_VF) {
+ stmt.opcode = INSTR_BITAND;
+ stmt.o1.s1 = ir_value_code_addr(instr->_ops[1]);
+ stmt.o2.s1 = ir_value_code_addr(instr->_ops[2]);
+ stmt.o3.s1 = ir_value_code_addr(instr->_ops[0]);
+ code_push_statement(code, &stmt, instr->context);
+ ++stmt.o1.s1;
+ ++stmt.o3.s1;
+ code_push_statement(code, &stmt, instr->context);
+ ++stmt.o1.s1;
+ ++stmt.o3.s1;
+ code_push_statement(code, &stmt, instr->context);
+
+ /* instruction generated */
+ continue;
+ }
+
+ if (instr->opcode == VINSTR_BITOR_VF) {
+ stmt.opcode = INSTR_BITOR;
+ stmt.o1.s1 = ir_value_code_addr(instr->_ops[1]);
+ stmt.o2.s1 = ir_value_code_addr(instr->_ops[2]);
+ stmt.o3.s1 = ir_value_code_addr(instr->_ops[0]);
+ code_push_statement(code, &stmt, instr->context);
+ ++stmt.o1.s1;
+ ++stmt.o3.s1;
+ code_push_statement(code, &stmt, instr->context);
+ ++stmt.o1.s1;
+ ++stmt.o3.s1;
+ code_push_statement(code, &stmt, instr->context);
+
+ /* instruction generated */
+ continue;
+ }
+
+ if (instr->opcode == VINSTR_BITXOR_VF) {
+ for (j = 0; j < 3; ++j) {
+ stmt.opcode = INSTR_BITOR;
+ stmt.o1.s1 = ir_value_code_addr(instr->_ops[1]) + j;
+ stmt.o2.s1 = ir_value_code_addr(instr->_ops[2]);
+ stmt.o3.s1 = ir_value_code_addr(instr->_ops[0]) + j;
+ code_push_statement(code, &stmt, instr->context);
+ stmt.opcode = INSTR_BITAND;
+ stmt.o1.s1 = ir_value_code_addr(instr->_ops[1]) + j;
+ stmt.o2.s1 = ir_value_code_addr(instr->_ops[2]);
+ stmt.o3.s1 = ir_value_code_addr(func->owner->vinstr_temp[0]) + j;
+ code_push_statement(code, &stmt, instr->context);
+ }
+ stmt.opcode = INSTR_SUB_V;
+ stmt.o1.s1 = ir_value_code_addr(instr->_ops[0]);
+ stmt.o2.s1 = ir_value_code_addr(func->owner->vinstr_temp[0]);
+ stmt.o3.s1 = ir_value_code_addr(instr->_ops[0]);
+ code_push_statement(code, &stmt, instr->context);
+
+ /* instruction generated */
+ continue;
+ }
+
+ if (instr->opcode == VINSTR_CROSS) {
+ stmt.opcode = INSTR_MUL_F;
+ for (j = 0; j < 3; ++j) {
+ stmt.o1.s1 = ir_value_code_addr(instr->_ops[1]) + (j + 1) % 3;
+ stmt.o2.s1 = ir_value_code_addr(instr->_ops[2]) + (j + 2) % 3;
+ stmt.o3.s1 = ir_value_code_addr(instr->_ops[0]) + j;
+ code_push_statement(code, &stmt, instr->context);
+ stmt.o1.s1 = ir_value_code_addr(instr->_ops[1]) + (j + 2) % 3;
+ stmt.o2.s1 = ir_value_code_addr(instr->_ops[2]) + (j + 1) % 3;
+ stmt.o3.s1 = ir_value_code_addr(func->owner->vinstr_temp[0]) + j;
+ code_push_statement(code, &stmt, instr->context);
+ }
+ stmt.opcode = INSTR_SUB_V;
+ stmt.o1.s1 = ir_value_code_addr(instr->_ops[0]);
+ stmt.o2.s1 = ir_value_code_addr(func->owner->vinstr_temp[0]);
+ stmt.o3.s1 = ir_value_code_addr(instr->_ops[0]);
+ code_push_statement(code, &stmt, instr->context);
+
+ /* instruction generated */
+ continue;
+ }
+
if (instr->opcode == VINSTR_COND) {
ontrue = instr->bops[0];
onfalse = instr->bops[1];
stmt.opcode = INSTR_IF;
stmt.o2.s1 = (ontrue->code_start) - vec_size(code->statements);
if (stmt.o2.s1 != 1)
- code_push_statement(code, &stmt, instr->context.line);
+ code_push_statement(code, &stmt, instr->context);
}
if (onfalse->generated) {
stmt.opcode = INSTR_IFNOT;
stmt.o2.s1 = (onfalse->code_start) - vec_size(code->statements);
if (stmt.o2.s1 != 1)
- code_push_statement(code, &stmt, instr->context.line);
+ code_push_statement(code, &stmt, instr->context);
}
if (!ontrue->generated) {
if (onfalse->generated)
ontrue = tmp;
}
stidx = vec_size(code->statements);
- code_push_statement(code, &stmt, instr->context.line);
+ code_push_statement(code, &stmt, instr->context);
/* on false we jump, so add ontrue-path */
if (!gen_blocks_recursive(code, func, ontrue))
return false;
stmt.o2.s1 = 0;
stmt.o3.s1 = 0;
if (stmt.o1.s1 != 1)
- code_push_statement(code, &stmt, instr->context.line);
+ code_push_statement(code, &stmt, instr->context);
return true;
}
else if (stidx+2 == vec_size(code->statements) && code->statements[stidx].o2.s1 == 1) {
stmt.opcode = type_store_instr[param->vtype];
stmt.o1.u1 = ir_value_code_addr(param);
stmt.o2.u1 = OFS_PARM0 + 3 * p;
- code_push_statement(code, &stmt, instr->context.line);
+ code_push_statement(code, &stmt, instr->context);
}
/* Now handle extparams */
first = vec_size(instr->params);
stmt.opcode = type_store_instr[param->vtype];
stmt.o1.u1 = ir_value_code_addr(param);
stmt.o2.u1 = ir_value_code_addr(targetparam);
- code_push_statement(code, &stmt, instr->context.line);
+ code_push_statement(code, &stmt, instr->context);
}
stmt.opcode = INSTR_CALL0 + vec_size(instr->params);
stmt.o1.u1 = ir_value_code_addr(instr->_ops[1]);
stmt.o2.u1 = 0;
stmt.o3.u1 = 0;
- code_push_statement(code, &stmt, instr->context.line);
+ code_push_statement(code, &stmt, instr->context);
retvalue = instr->_ops[0];
if (retvalue && retvalue->store != store_return &&
stmt.o1.u1 = OFS_RETURN;
stmt.o2.u1 = ir_value_code_addr(retvalue);
stmt.o3.u1 = 0;
- code_push_statement(code, &stmt, instr->context.line);
+ code_push_statement(code, &stmt, instr->context);
}
continue;
}
}
}
- code_push_statement(code, &stmt, instr->context.line);
+ code_push_statement(code, &stmt, instr->context);
}
return true;
}
retst->opcode = INSTR_DONE;
++opts_optimizationcount[OPTIM_VOID_RETURN];
} else {
+ lex_ctx_t last;
+
stmt.opcode = INSTR_DONE;
- stmt.o1.u1 = 0;
- stmt.o2.u1 = 0;
- stmt.o3.u1 = 0;
- code_push_statement(code, &stmt, vec_last(code->linenums));
+ stmt.o1.u1 = 0;
+ stmt.o2.u1 = 0;
+ stmt.o3.u1 = 0;
+ last.line = vec_last(code->linenums);
+ last.column = vec_last(code->columnnums);
+
+ code_push_statement(code, &stmt, last);
}
return true;
}
}
stmt.o1.u1 = ir_value_code_addr(ep);
stmt.o2.u1 = ir_value_code_addr(self->locals[i]);
- code_push_statement(code, &stmt, self->context.line);
+ code_push_statement(code, &stmt, self->context);
}
return true;
if (i < 8) {
stmt.o1.u1 = OFS_PARM0 + 3*i;
stmt.o2.u1 = ir_value_code_addr(self->locals[i]);
- code_push_statement(code, &stmt, self->context.line);
+ code_push_statement(code, &stmt, self->context);
continue;
}
ext = i - 8;
stmt.o1.u1 = ir_value_code_addr(ep);
stmt.o2.u1 = ir_value_code_addr(self->locals[i]);
- code_push_statement(code, &stmt, self->context.line);
+ code_push_statement(code, &stmt, self->context);
}
return true;
if (irfun->builtin)
return true;
+ /*
+ * If there is no definition and the thing is eraseable, we can ignore
+ * outputting the function to begin with.
+ */
+ if (global->flags & IR_FLAG_ERASEABLE && irfun->code_function_def < 0) {
+ return true;
+ }
+
if (irfun->code_function_def < 0) {
irerror(irfun->context, "`%s`: IR global wasn't generated, failed to access function-def", irfun->name);
return false;
{
pushdef = true;
+ /*
+ * if we're eraseable and the function isn't referenced ignore outputting
+ * the function.
+ */
+ if (global->flags & IR_FLAG_ERASEABLE && vec_size(global->reads) == 0) {
+ return true;
+ }
+
if (OPTS_OPTIMIZATION(OPTIM_STRIP_CONSTANT_NAMES) &&
!(global->flags & IR_FLAG_INCLUDE_DEF) &&
(global->name[0] == '#' || global->cvq == CV_CONST))
/* DP errors if the last instruction is not an INSTR_DONE. */
if (vec_last(self->code->statements).opcode != INSTR_DONE)
{
+ lex_ctx_t last;
+
stmt.opcode = INSTR_DONE;
- stmt.o1.u1 = 0;
- stmt.o2.u1 = 0;
- stmt.o3.u1 = 0;
- code_push_statement(self->code, &stmt, vec_last(self->code->linenums));
+ stmt.o1.u1 = 0;
+ stmt.o2.u1 = 0;
+ stmt.o3.u1 = 0;
+ last.line = vec_last(self->code->linenums);
+ last.column = vec_last(self->code->columnnums);
+
+ code_push_statement(self->code, &stmt, last);
}
if (OPTS_OPTION_BOOL(OPTION_PP_ONLY))
if (op < VINSTR_END)
return util_instr_str[op];
switch (op) {
- case VINSTR_END: return "END";
- case VINSTR_PHI: return "PHI";
- case VINSTR_JUMP: return "JUMP";
- case VINSTR_COND: return "COND";
- default: return "<UNK>";
+ case VINSTR_END: return "END";
+ case VINSTR_PHI: return "PHI";
+ case VINSTR_JUMP: return "JUMP";
+ case VINSTR_COND: return "COND";
+ case VINSTR_BITXOR: return "BITXOR";
+ case VINSTR_BITAND_V: return "BITAND_V";
+ case VINSTR_BITOR_V: return "BITOR_V";
+ case VINSTR_BITXOR_V: return "BITXOR_V";
+ case VINSTR_BITAND_VF: return "BITAND_VF";
+ case VINSTR_BITOR_VF: return "BITOR_VF";
+ case VINSTR_BITXOR_VF: return "BITXOR_VF";
+ case VINSTR_CROSS: return "CROSS";
+ default: return "<UNK>";
}
}