From: Dale Weiler Date: Sun, 16 Jun 2013 02:17:29 +0000 (+0000) Subject: Make ^ legal for vector ^ vector, and vector ^ float (read the huge comment that... X-Git-Tag: v0.3.0~122 X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=17ae2dbe4d5fa315d83e6a95f8969801f3d4c1c5;p=xonotic%2Fgmqcc.git Make ^ legal for vector ^ vector, and vector ^ float (read the huge comment that explains why and what this does). Currently only works for constants (don't know how to do expression for multiple vector components yet). --- diff --git a/parser.c b/parser.c index 7ba3782..cb4712a 100644 --- a/parser.c +++ b/parser.c @@ -1035,48 +1035,126 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) break; case opid1('^'): /* - * ^ can be implemented as: - * (LHS | RHS) & ~(LHS & RHS) - * to implement ~ we need to use -1-X, as you can see the - * whole process ends up becoming: - * (LHS | RHS) & (-1 - (LHS & RHS)) + * 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 (NotSameType(TYPE_FLOAT)) { + 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(CanConstFold(exprs[0], exprs[1])) { - out = (ast_expression*)parser_const_float(parser, (float)((qcint)(ConstF(0)) ^ ((qcint)(ConstF(1))))); - } else { - ast_binary *expr = ast_binary_new( - ctx, - INSTR_SUB_F, - (ast_expression*)parser_const_float_neg1(parser), - (ast_expression*)ast_binary_new( - ctx, - INSTR_BITAND, - exprs[0], - exprs[1] - ) - ); - expr->refs = AST_REF_NONE; - - out = (ast_expression*) - ast_binary_new( + /* + * IF the first expression is float, the following will be too + * since scalar ^ vector is not allowed. + */ + if (exprs[0]->vtype == TYPE_FLOAT) { + if(CanConstFold(exprs[0], exprs[1])) { + out = (ast_expression*)parser_const_float(parser, (float)((qcint)(ConstF(0)) ^ ((qcint)(ConstF(1))))); + } else { + ast_binary *expr = ast_binary_new( ctx, - INSTR_BITAND, + INSTR_SUB_F, + (ast_expression*)parser_const_float_neg1(parser), (ast_expression*)ast_binary_new( ctx, - INSTR_BITOR, + INSTR_BITAND, exprs[0], exprs[1] - ), - (ast_expression*)expr + ) ); + 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. + */ + if (CanConstFold(exprs[0], exprs[1])) { + out = (ast_expression*)parser_const_vector_f( + parser, + (float)(((qcint)(ConstV(0).x)) ^ ((qcint)(ConstV(1).x))), + (float)(((qcint)(ConstV(0).y)) ^ ((qcint)(ConstV(1).y))), + (float)(((qcint)(ConstV(0).z)) ^ ((qcint)(ConstV(1).z))) + ); + } else { + compile_error(ast_ctx(exprs[0]), "Not Yet Implemented: bit-xor for vector against vector"); + return false; + } + } else { + /* + * Xor all the values of the vector components against the + * scalar in question. + */ + if (CanConstFold(exprs[0], exprs[1])) { + out = (ast_expression*)parser_const_vector_f( + parser, + (float)(((qcint)(ConstV(0).x)) ^ ((qcint)(ConstF(1)))), + (float)(((qcint)(ConstV(0).y)) ^ ((qcint)(ConstF(1)))), + (float)(((qcint)(ConstV(0).z)) ^ ((qcint)(ConstF(1)))) + ); + } else { + compile_error(ast_ctx(exprs[0]), "Not Yet Implemented: bit-xor for vector against float"); + return false; + } + } } + break; case opid2('<','<'): diff --git a/tests/xor.qc b/tests/xor.qc index 2006944..b2820ef 100644 --- a/tests/xor.qc +++ b/tests/xor.qc @@ -21,4 +21,13 @@ void main() { // elements are their own inverse? if (x ^ 0 == x) print("inverse\n"); + + // vector ^ vector + // vector ^ float + // are legal in constant expressions (currently) + const vector v3 = '5 2 5' ^ '3 10 3'; + const vector v4 = '5 2 5' ^ 10; + + print("vv: ", vtos(v3), "\n"); + print("vf: ", vtos(v4), "\n"); } diff --git a/tests/xor.tmpl b/tests/xor.tmpl index 0116161..a2a4efc 100644 --- a/tests/xor.tmpl +++ b/tests/xor.tmpl @@ -8,3 +8,5 @@ M: 8 M: commutative M: assocative M: inverse +M: vv: '6 8 6' +M: vf: '15 8 15'