(op >= INSTR_NOT_F && op <= INSTR_NOT_FNC) ||
(op >= INSTR_AND && op <= INSTR_BITOR) ||
(op >= INSTR_CALL0 && op <= INSTR_CALL8) ||
- (op == VINSTR_BITAND_VV) ||
+ (op == VINSTR_BITXOR) ||
+ (op == VINSTR_BITAND_V) ||
(op == VINSTR_BITAND_VF) ||
- (op == VINSTR_BITOR_VV) ||
- (op == VINSTR_BITOR_VF));
+ (op == VINSTR_BITOR_V) ||
+ (op == VINSTR_BITOR_VF) ||
+ (op == VINSTR_BITXOR_V) ||
+ (op == VINSTR_BITXOR_VF));
}
static bool ir_function_pass_peephole(ir_function *self)
continue;
}
+ /* Emulated bitxor cannot deal with aliased inputs. */
+ if (oper->opcode == VINSTR_BITXOR && oper->_ops[2]->memberof == oper->_ops[1])
+ continue;
+
/* Emulated bitand/bitor for vector+float cannot deal with aliased inputs. */
if (oper->opcode == VINSTR_BITAND_VF && oper->_ops[2]->memberof == oper->_ops[1])
continue;
if (oper->opcode == VINSTR_BITOR_VF && oper->_ops[2]->memberof == oper->_ops[1])
continue;
+ if (oper->opcode == VINSTR_BITXOR_VF && oper->_ops[2]->memberof == oper->_ops[1])
+ continue;
value = oper->_ops[0];
#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_VV:
- case VINSTR_BITOR_VV:
+ case VINSTR_BITAND_V:
+ case VINSTR_BITOR_V:
+ case VINSTR_BITXOR_V:
case VINSTR_BITAND_VF:
case VINSTR_BITOR_VF:
+ case VINSTR_BITXOR_VF:
#if 0
case INSTR_DIV_VF:
case INSTR_MUL_IV:
* same source and destination operand otherwise, as the engine may
* read the source multiple times. */
if (instr->opcode == INSTR_MUL_VF ||
+ instr->opcode == VINSTR_BITXOR ||
instr->opcode == VINSTR_BITAND_VF ||
- instr->opcode == VINSTR_BITOR_VF)
+ instr->opcode == VINSTR_BITOR_VF ||
+ instr->opcode == VINSTR_BITXOR_VF ||
+ instr->opcode == VINSTR_BITXOR_V)
{
value = instr->_ops[2];
/* 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);
return true;
}
- if (instr->opcode == VINSTR_BITAND_VV) {
+ 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.line);
+ 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.line);
+ 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.line);
+
+ /* 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]);
continue;
}
- if (instr->opcode == VINSTR_BITOR_VV) {
+ 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]);
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.line);
+ 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.line);
+ }
+ 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.line);
+
+ /* instruction generated */
+ continue;
+ }
+
if (instr->opcode == VINSTR_BITAND_VF) {
stmt.opcode = INSTR_BITAND;
stmt.o1.s1 = ir_value_code_addr(instr->_ops[1]);
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.line);
+ 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.line);
+ }
+ 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.line);
+
+ /* instruction generated */
+ continue;
+ }
+
if (instr->opcode == VINSTR_COND) {
ontrue = instr->bops[0];
onfalse = instr->bops[1];
case VINSTR_PHI: return "PHI";
case VINSTR_JUMP: return "JUMP";
case VINSTR_COND: return "COND";
- case VINSTR_BITAND_VV: return "BITAND_VV";
- case VINSTR_BITOR_VV: return "BITOR_VV";
+ 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";
default: return "<UNK>";
}
}
case opid1('|'):
case opid1('&'):
+ case opid1('^'):
if ( !(exprs[0]->vtype == TYPE_FLOAT && exprs[1]->vtype == TYPE_FLOAT) &&
!(exprs[0]->vtype == TYPE_VECTOR && exprs[1]->vtype == TYPE_FLOAT) &&
!(exprs[0]->vtype == TYPE_VECTOR && exprs[1]->vtype == TYPE_VECTOR))
*/
if (exprs[0]->vtype == TYPE_FLOAT) {
out = (ast_expression*)ast_binary_new(ctx,
- (op->id == opid1('|') ? INSTR_BITOR : INSTR_BITAND),
+ (op->id == opid1('^') ? VINSTR_BITXOR : op->id == opid1('|') ? INSTR_BITOR : INSTR_BITAND),
exprs[0], exprs[1]);
} else {
/*
- * The first is a vector: vector is allowed to xor with vector and
+ * The first is a vector: vector is allowed to bitop with vector and
* with scalar, branch here for the second operand.
*/
if (exprs[1]->vtype == TYPE_VECTOR) {
/*
- * Xor all the values of the vector components against the
+ * Bitop all the values of the vector components against the
* vectors components in question.
*/
out = (ast_expression*)ast_binary_new(ctx,
- (op->id == opid1('|') ? VINSTR_BITOR_VV : VINSTR_BITAND_VV),
+ (op->id == opid1('^') ? VINSTR_BITXOR_V : op->id == opid1('|') ? VINSTR_BITOR_V : VINSTR_BITAND_V),
exprs[0], exprs[1]);
} else {
out = (ast_expression*)ast_binary_new(ctx,
- (op->id == opid1('|') ? VINSTR_BITOR_VF : VINSTR_BITAND_VF),
+ (op->id == opid1('^') ? VINSTR_BITXOR_VF : op->id == opid1('|') ? VINSTR_BITOR_VF : VINSTR_BITAND_VF),
exprs[0], exprs[1]);
}
}
}
break;
- case opid1('^'):
- /*
- * Okay lets designate what the hell is an acceptable use
- * of the ^ operator. In many vector processing units, XOR
- * is allowed to be used on vectors, but only if the first
- * operand is a vector, the second operand can be a float
- * or vector. It's never legal for the first operand to be
- * a float, and then the following operand to be a vector.
- * Further more, the only time it is legal to do XOR otherwise
- * is when both operand are floats. This nicely crafted if
- * statement catches them all.
- *
- * In the event that the first operand is a vector, two
- * possible situations can arise, thus, each element of
- * vector A (operand A) is exclusive-ORed with the corresponding
- * element of vector B (operand B), If B is scalar, the
- * scalar value is first replicated for each element.
- *
- * The QCVM itself lacks a BITXOR instruction. Thus emulating
- * the mathematics of it is required. The following equation
- * is used: (LHS | RHS) & ~(LHS & RHS). However, due to the
- * QCVM also lacking a BITNEG instruction, we need to emulate
- * ~FOO with -1 - FOO, the whole process becoming this nicely
- * crafted expression: (LHS | RHS) & (-1 - (LHS & RHS)).
- *
- * When A is not scalar, this process is repeated for all
- * components of vector A with the value in operand B,
- * only if operand B is scalar. When A is not scalar, and B
- * is also not scalar, this process is repeated for all
- * components of the vector A with the components of vector B.
- * Finally when A is scalar and B is scalar, this process is
- * simply used once for A and B being LHS and RHS respectfully.
- *
- * Yes the semantics are a bit strange (no pun intended).
- * But then again BITXOR is strange itself, consdering it's
- * commutative, assocative, and elements of the BITXOR operation
- * are their own inverse.
- */
- if ( !(exprs[0]->vtype == TYPE_FLOAT && exprs[1]->vtype == TYPE_FLOAT) &&
- !(exprs[0]->vtype == TYPE_VECTOR && exprs[1]->vtype == TYPE_FLOAT) &&
- !(exprs[0]->vtype == TYPE_VECTOR && exprs[1]->vtype == TYPE_VECTOR))
- {
- compile_error(ctx, "invalid types used in expression: cannot perform bit operations between types %s and %s",
- type_name[exprs[0]->vtype],
- type_name[exprs[1]->vtype]);
- return false;
- }
-
- if (!(out = fold_op(parser->fold, op, exprs))) {
- /*
- * IF the first expression is float, the following will be too
- * since scalar ^ vector is not allowed.
- */
- if (exprs[0]->vtype == TYPE_FLOAT) {
- ast_binary *expr = ast_binary_new(
- ctx,
- INSTR_SUB_F,
- (ast_expression*)parser->fold->imm_float[2],
- (ast_expression*)ast_binary_new(
- ctx,
- INSTR_BITAND,
- exprs[0],
- exprs[1]
- )
- );
- expr->refs = AST_REF_NONE;
-
- out = (ast_expression*)
- ast_binary_new(
- ctx,
- INSTR_BITAND,
- (ast_expression*)ast_binary_new(
- ctx,
- INSTR_BITOR,
- exprs[0],
- exprs[1]
- ),
- (ast_expression*)expr
- );
- } else {
- /*
- * The first is a vector: vector is allowed to xor with vector and
- * with scalar, branch here for the second operand.
- */
- if (exprs[1]->vtype == TYPE_VECTOR) {
- /*
- * Xor all the values of the vector components against the
- * vectors components in question.
- */
- compile_error(ast_ctx(exprs[0]), "Not Yet Implemented: bit-xor for vector against vector");
- return false;
- } else {
- compile_error(ast_ctx(exprs[0]), "Not Yet Implemented: bit-xor for vector against float");
- return false;
- }
- }
- }
- break;
case opid2('<','<'):
case opid2('>','>'):