static void draw_binary_vec4_le(ivl_expr_t expr) { ivl_expr_t le = ivl_expr_oper1(expr); ivl_expr_t re = ivl_expr_oper2(expr); ivl_expr_t tmp; if ((ivl_expr_value(le) == IVL_VT_REAL) || (ivl_expr_value(re) == IVL_VT_REAL)) { draw_binary_vec4_le_real(expr); return; } char use_opcode = ivl_expr_opcode(expr); char s_flag = (ivl_expr_signed(le) && ivl_expr_signed(re)) ? 's' : 'u'; /* If this is a > or >=, then convert it to < or <= by swapping the operands. Adjust the opcode to match. */ switch (use_opcode) { case 'G': tmp = le; le = re; re = tmp; use_opcode = 'L'; break; case '>': tmp = le; le = re; re = tmp; use_opcode = '<'; break; } if ((ivl_expr_value(le)==IVL_VT_STRING) && (ivl_expr_value(re)==IVL_VT_STRING)) { draw_binary_vec4_le_string(expr); return; } if ((ivl_expr_value(le)==IVL_VT_STRING) && (ivl_expr_type(re)==IVL_EX_STRING)) { draw_binary_vec4_le_string(expr); return; } if ((ivl_expr_type(le)==IVL_EX_STRING) && (ivl_expr_value(re)==IVL_VT_STRING)) { draw_binary_vec4_le_string(expr); return; } /* NOTE: I think I would rather the elaborator handle the operand widths. When that happens, take this code out. */ unsigned use_wid = ivl_expr_width(le); if (ivl_expr_width(re) > use_wid) use_wid = ivl_expr_width(re); draw_eval_vec4(le); resize_vec4_wid(le, use_wid); if (ivl_expr_width(re)==use_wid && test_immediate_vec4_ok(re)) { /* Special case: If the right operand can be handled as an immediate operand, then use that instead. */ char opcode[8]; snprintf(opcode, sizeof opcode, "%%cmpi/%c", s_flag); draw_immediate_vec4(re, opcode); } else { draw_eval_vec4(re); resize_vec4_wid(re, use_wid); fprintf(vvp_out, " %%cmp/%c;\n", s_flag); } switch (use_opcode) { case 'L': fprintf(vvp_out, " %%flag_get/vec4 4;\n"); fprintf(vvp_out, " %%flag_get/vec4 5;\n"); fprintf(vvp_out, " %%or;\n"); break; case '<': fprintf(vvp_out, " %%flag_get/vec4 5;\n"); break; default: assert(0); break; } }
static void draw_binary_vec4_compare(ivl_expr_t expr) { ivl_expr_t le = ivl_expr_oper1(expr); ivl_expr_t re = ivl_expr_oper2(expr); if ((ivl_expr_value(le) == IVL_VT_REAL) || (ivl_expr_value(re) == IVL_VT_REAL)) { draw_binary_vec4_compare_real(expr); return; } if ((ivl_expr_value(le)==IVL_VT_STRING) && (ivl_expr_value(re)==IVL_VT_STRING)) { draw_binary_vec4_compare_string(expr); return; } if ((ivl_expr_value(le)==IVL_VT_STRING) && (ivl_expr_type(re)==IVL_EX_STRING)) { draw_binary_vec4_compare_string(expr); return; } if ((ivl_expr_type(le)==IVL_EX_STRING) && (ivl_expr_value(re)==IVL_VT_STRING)) { draw_binary_vec4_compare_string(expr); return; } if ((ivl_expr_value(le)==IVL_VT_CLASS) && (ivl_expr_value(re)==IVL_VT_CLASS)) { draw_binary_vec4_compare_class(expr); return; } unsigned use_wid = ivl_expr_width(le); if (ivl_expr_width(re) > use_wid) use_wid = ivl_expr_width(re); draw_eval_vec4(le); resize_vec4_wid(le, use_wid); draw_eval_vec4(re); resize_vec4_wid(re, use_wid); switch (ivl_expr_opcode(expr)) { case 'e': /* == */ fprintf(vvp_out, " %%cmp/e;\n"); fprintf(vvp_out, " %%flag_get/vec4 4;\n"); break; case 'n': /* != */ fprintf(vvp_out, " %%cmp/e;\n"); fprintf(vvp_out, " %%flag_inv 4;\n"); fprintf(vvp_out, " %%flag_get/vec4 4;\n"); break; case 'E': /* === */ fprintf(vvp_out, " %%cmp/e;\n"); fprintf(vvp_out, " %%flag_get/vec4 6;\n"); break; case 'N': /* !== */ fprintf(vvp_out, " %%cmp/e;\n"); fprintf(vvp_out, " %%flag_inv 6;\n"); fprintf(vvp_out, " %%flag_get/vec4 6;\n"); break; default: assert(0); } }
static int show_stmt_assign_vector(ivl_statement_t net) { ivl_expr_t rval = ivl_stmt_rval(net); //struct vector_info res; //struct vector_info lres = {0, 0}; struct vec_slice_info*slices = 0; int idx_reg; /* If this is a compressed assignment, then get the contents of the l-value. We need these values as part of the r-value calculation. */ if (ivl_stmt_opcode(net) != 0) { slices = calloc(ivl_stmt_lvals(net), sizeof(struct vec_slice_info)); get_vec_from_lval(net, slices); } /* Handle the special case that the expression is a real value. Evaluate the real expression, then convert the result to a vector. Then store that vector into the l-value. */ if (ivl_expr_value(rval) == IVL_VT_REAL) { draw_eval_real(rval); /* This is the accumulated with of the l-value of the assignment. */ unsigned wid = ivl_stmt_lwidth(net); /* Convert a calculated real value to a vec4 value of the given width. We need to include the width of the result because real values to not have any inherit width. The real value will be popped, and a vec4 value pushed. */ fprintf(vvp_out, " %%cvt/vr %u;\n", wid); } else if (ivl_expr_value(rval) == IVL_VT_STRING) { /* Special case: vector to string casting */ ivl_lval_t lval = ivl_stmt_lval(net, 0); fprintf(vvp_out, " %%vpi_call %u %u \"$ivl_string_method$to_vec\", v%p_0, v%p_0 {0 0 0};\n", ivl_file_table_index(ivl_stmt_file(net)), ivl_stmt_lineno(net), ivl_expr_signal(rval), ivl_lval_sig(lval)); return 0; } else { unsigned wid = ivl_stmt_lwidth(net); draw_eval_vec4(rval); resize_vec4_wid(rval, wid); } switch (ivl_stmt_opcode(net)) { case 0: store_vec4_to_lval(net); break; case '+': fprintf(vvp_out, " %%add;\n"); put_vec_to_lval(net, slices); break; case '-': fprintf(vvp_out, " %%sub;\n"); put_vec_to_lval(net, slices); break; case '*': fprintf(vvp_out, " %%mul;\n"); put_vec_to_lval(net, slices); break; case '/': fprintf(vvp_out, " %%div%s;\n", ivl_expr_signed(rval)? "/s":""); put_vec_to_lval(net, slices); break; case '%': fprintf(vvp_out, " %%mod%s;\n", ivl_expr_signed(rval)? "/s":""); put_vec_to_lval(net, slices); break; case '&': fprintf(vvp_out, " %%and;\n"); put_vec_to_lval(net, slices); break; case '|': fprintf(vvp_out, " %%or;\n"); put_vec_to_lval(net, slices); break; case '^': fprintf(vvp_out, " %%xor;\n"); put_vec_to_lval(net, slices); break; case 'l': /* lval <<= expr */ idx_reg = allocate_word(); fprintf(vvp_out, " %%ix/vec4 %d;\n", idx_reg); fprintf(vvp_out, " %%shiftl %d;\n", idx_reg); clr_word(idx_reg); put_vec_to_lval(net, slices); break; case 'r': /* lval >>= expr */ idx_reg = allocate_word(); fprintf(vvp_out, " %%ix/vec4 %d;\n", idx_reg); fprintf(vvp_out, " %%shiftr %d;\n", idx_reg); clr_word(idx_reg); put_vec_to_lval(net, slices); break; case 'R': /* lval >>>= expr */ idx_reg = allocate_word(); fprintf(vvp_out, " %%ix/vec4 %d;\n", idx_reg); fprintf(vvp_out, " %%shiftr/s %d;\n", idx_reg); clr_word(idx_reg); put_vec_to_lval(net, slices); break; default: fprintf(vvp_out, "; UNSUPPORTED ASSIGNMENT OPCODE: %c\n", ivl_stmt_opcode(net)); assert(0); break; } if (slices) free(slices); return 0; }
static void draw_unary_vec4(ivl_expr_t expr) { ivl_expr_t sub = ivl_expr_oper1(expr); if (debug_draw) { fprintf(vvp_out, " ; %s:%u:draw_unary_vec4: opcode=%c\n", ivl_expr_file(expr), ivl_expr_lineno(expr), ivl_expr_opcode(expr)); } switch (ivl_expr_opcode(expr)) { case '&': draw_eval_vec4(sub); fprintf(vvp_out, " %%and/r;\n"); break; case '|': draw_eval_vec4(sub); fprintf(vvp_out, " %%or/r;\n"); break; case '^': draw_eval_vec4(sub); fprintf(vvp_out, " %%xor/r;\n"); break; case '~': draw_eval_vec4(sub); fprintf(vvp_out, " %%inv;\n"); break; case '!': draw_eval_vec4(sub); fprintf(vvp_out, " %%nor/r;\n"); break; case '-': draw_eval_vec4(sub); fprintf(vvp_out, " %%inv;\n"); fprintf(vvp_out, " %%pushi/vec4 1, 0, %u;\n", ivl_expr_width(sub)); fprintf(vvp_out, " %%add;\n"); break; case 'A': /* nand (~&) */ draw_eval_vec4(sub); fprintf(vvp_out, " %%nand/r;\n"); break; case 'D': /* pre-decrement (--x) */ draw_unary_inc_dec(sub, false, true); break; case 'd': /* post_decrement (x--) */ draw_unary_inc_dec(sub, false, false); break; case 'I': /* pre-increment (++x) */ draw_unary_inc_dec(sub, true, true); break; case 'i': /* post-increment (x++) */ draw_unary_inc_dec(sub, true, false); break; case 'N': /* nor (~|) */ draw_eval_vec4(sub); fprintf(vvp_out, " %%nor/r;\n"); break; case 'X': /* xnor (~^) */ draw_eval_vec4(sub); fprintf(vvp_out, " %%xnor/r;\n"); break; case 'm': /* abs(m) */ draw_eval_vec4(sub); if (! ivl_expr_signed(sub)) break; /* Test if (m) < 0 */ fprintf(vvp_out, " %%dup/vec4;\n"); fprintf(vvp_out, " %%pushi/vec4 0, 0, %u;\n", ivl_expr_width(sub)); fprintf(vvp_out, " %%cmp/s;\n"); fprintf(vvp_out, " %%jmp/0xz T_%u.%u, 5;\n", thread_count, local_count); /* If so, calculate -(m) */ fprintf(vvp_out, " %%inv;\n"); fprintf(vvp_out, " %%pushi/vec4 1, 0, %u;\n", ivl_expr_width(sub)); fprintf(vvp_out, " %%add;\n"); fprintf(vvp_out, "T_%u.%u ;\n", thread_count, local_count); local_count += 1; break; case 'v': /* Cast real to vec4 */ assert(ivl_expr_value(sub) == IVL_VT_REAL); draw_eval_real(sub); fprintf(vvp_out, " %%cvt/vr %u;\n", ivl_expr_width(expr)); break; case '2': /* Cast expression to bool */ switch (ivl_expr_value(sub)) { case IVL_VT_LOGIC: draw_eval_vec4(sub); fprintf(vvp_out, " %%cast2;\n"); resize_vec4_wid(sub, ivl_expr_width(expr)); break; case IVL_VT_BOOL: draw_eval_vec4(sub); resize_vec4_wid(sub, ivl_expr_width(expr)); break; case IVL_VT_REAL: draw_eval_real(sub); fprintf(vvp_out, " %%cvt/vr %u;\n", ivl_expr_width(expr)); break; default: assert(0); break; } break; default: fprintf(stderr, "XXXX Unary operator %c not implemented\n", ivl_expr_opcode(expr)); break; } }
static int draw_condition_binary_compare(ivl_expr_t expr) { ivl_expr_t le = ivl_expr_oper1(expr); ivl_expr_t re = ivl_expr_oper2(expr); if ((ivl_expr_value(le) == IVL_VT_REAL) || (ivl_expr_value(re) == IVL_VT_REAL)) { return draw_condition_fallback(expr); } if ((ivl_expr_value(le)==IVL_VT_STRING) && (ivl_expr_value(re)==IVL_VT_STRING)) { return draw_condition_fallback(expr); } if ((ivl_expr_value(le)==IVL_VT_STRING) && (ivl_expr_type(re)==IVL_EX_STRING)) { return draw_condition_fallback(expr); } if ((ivl_expr_type(le)==IVL_EX_STRING) && (ivl_expr_value(re)==IVL_VT_STRING)) { return draw_condition_fallback(expr); } if ((ivl_expr_value(le)==IVL_VT_CLASS) && (ivl_expr_value(re)==IVL_VT_CLASS)) { return draw_condition_fallback(expr); } unsigned use_wid = ivl_expr_width(le); if (ivl_expr_width(re) > use_wid) use_wid = ivl_expr_width(re); /* If the le is constant, then swap the operands so that we can possibly take advantage of the immediate version of the %cmp instruction. */ if (ivl_expr_width(le)==use_wid && test_immediate_vec4_ok(le)) { ivl_expr_t tmp = le; re = le; le = tmp; } draw_eval_vec4(le); resize_vec4_wid(le, use_wid); char use_opcode = ivl_expr_opcode(expr); if (ivl_expr_width(re)==use_wid && test_immediate_vec4_ok(re)) { /* Special case: If the right operand can be handled as an immediate operand, then use that instead. */ if (use_opcode=='n' || use_opcode=='N') draw_immediate_vec4(re, "%cmpi/ne"); else draw_immediate_vec4(re, "%cmpi/e"); } else { draw_eval_vec4(re); resize_vec4_wid(re, use_wid); if (use_opcode=='n' || use_opcode=='N') fprintf(vvp_out, " %%cmp/ne;\n"); else fprintf(vvp_out, " %%cmp/e;\n"); } switch (ivl_expr_opcode(expr)) { case 'n': /* != */ case 'e': /* == */ return 4; break; case 'N': /* !== */ case 'E': /* === */ return 6; default: assert(0); return -1; } }