static GLboolean print_mov( struct tnl_clipspace_codegen *p, GLint dest, GLint src ) { return emit(p, " ") && emit_reg(p, dest) && emit(p, " = ") && emit_reg(p, src) && emit(p, ";\n"); }
static GLboolean print_float_to_chan( struct tnl_clipspace_codegen *p, GLint dest, GLint src ) { return emit(p, " ") && emit(p, "UNCLAMPED_FLOAT_TO_CHAN(") && emit_reg(p, dest) && emit(p, ", ") && emit_reg(p, src) && emit(p, ");\n"); }
static GLboolean print_mad( struct tnl_clipspace_codegen *p, GLint dest, GLint src0, GLint src1, GLint src2 ) { return emit(p, " ") && emit_reg(p, dest) && emit(p, " = ") && emit_reg(p, src0) && emit(p, " * ") && emit_reg(p, src1) && emit(p, " + ") && emit_reg(p, src2) && emit(p, ";\n"); }
static GLboolean print_const_ubyte( struct tnl_clipspace_codegen *p, GLint dest, GLubyte c ) { return emit(p, " ") && emit_reg(p, dest) && emit(p, " = %x;\n", c); }
static GLboolean print_const( struct tnl_clipspace_codegen *p, GLint dest, GLfloat c ) { return emit(p, " ") && emit_reg(p, dest) && emit(p, " = %g;\n", c); }
static GLboolean print_const_chan( struct tnl_clipspace_codegen *p, GLint dest, GLchan c ) { return emit(p, " ") && emit_reg(p, dest) && emit(p, " = ") && #if CHAN_TYPE == GL_FLOAT emit(p, "%f", c) && #else emit(p, "%d", c) && #endif emit(p, ";\n"); }
enum eval_result_type compile_bytecodes (struct agent_expr *aexpr) { int pc = 0; int done = 0; unsigned char op, next_op; int arg; /* This is only used to build 64-bit value for constants. */ ULONGEST top; struct bytecode_address *aentry, *aentry2; #define UNHANDLED \ do \ { \ ax_debug ("Cannot compile op 0x%x\n", op); \ return expr_eval_unhandled_opcode; \ } while (0) if (aexpr->length == 0) { ax_debug ("empty agent expression\n"); return expr_eval_empty_expression; } bytecode_address_table = NULL; while (!done) { op = aexpr->bytes[pc]; ax_debug ("About to compile op 0x%x, pc=%d\n", op, pc); /* Record the compiled-code address of the bytecode, for use by jump instructions. */ aentry = XNEW (struct bytecode_address); aentry->pc = pc; aentry->address = current_insn_ptr; aentry->goto_pc = -1; aentry->from_offset = aentry->from_size = 0; aentry->next = bytecode_address_table; bytecode_address_table = aentry; ++pc; emit_error = 0; switch (op) { case gdb_agent_op_add: emit_add (); break; case gdb_agent_op_sub: emit_sub (); break; case gdb_agent_op_mul: emit_mul (); break; case gdb_agent_op_div_signed: UNHANDLED; break; case gdb_agent_op_div_unsigned: UNHANDLED; break; case gdb_agent_op_rem_signed: UNHANDLED; break; case gdb_agent_op_rem_unsigned: UNHANDLED; break; case gdb_agent_op_lsh: emit_lsh (); break; case gdb_agent_op_rsh_signed: emit_rsh_signed (); break; case gdb_agent_op_rsh_unsigned: emit_rsh_unsigned (); break; case gdb_agent_op_trace: UNHANDLED; break; case gdb_agent_op_trace_quick: UNHANDLED; break; case gdb_agent_op_log_not: emit_log_not (); break; case gdb_agent_op_bit_and: emit_bit_and (); break; case gdb_agent_op_bit_or: emit_bit_or (); break; case gdb_agent_op_bit_xor: emit_bit_xor (); break; case gdb_agent_op_bit_not: emit_bit_not (); break; case gdb_agent_op_equal: next_op = aexpr->bytes[pc]; if (next_op == gdb_agent_op_if_goto && !is_goto_target (aexpr, pc) && target_emit_ops ()->emit_eq_goto) { ax_debug ("Combining equal & if_goto"); pc += 1; aentry->pc = pc; arg = aexpr->bytes[pc++]; arg = (arg << 8) + aexpr->bytes[pc++]; aentry->goto_pc = arg; emit_eq_goto (&(aentry->from_offset), &(aentry->from_size)); } else if (next_op == gdb_agent_op_log_not && (aexpr->bytes[pc + 1] == gdb_agent_op_if_goto) && !is_goto_target (aexpr, pc + 1) && target_emit_ops ()->emit_ne_goto) { ax_debug ("Combining equal & log_not & if_goto"); pc += 2; aentry->pc = pc; arg = aexpr->bytes[pc++]; arg = (arg << 8) + aexpr->bytes[pc++]; aentry->goto_pc = arg; emit_ne_goto (&(aentry->from_offset), &(aentry->from_size)); } else emit_equal (); break; case gdb_agent_op_less_signed: next_op = aexpr->bytes[pc]; if (next_op == gdb_agent_op_if_goto && !is_goto_target (aexpr, pc)) { ax_debug ("Combining less_signed & if_goto"); pc += 1; aentry->pc = pc; arg = aexpr->bytes[pc++]; arg = (arg << 8) + aexpr->bytes[pc++]; aentry->goto_pc = arg; emit_lt_goto (&(aentry->from_offset), &(aentry->from_size)); } else if (next_op == gdb_agent_op_log_not && !is_goto_target (aexpr, pc) && (aexpr->bytes[pc + 1] == gdb_agent_op_if_goto) && !is_goto_target (aexpr, pc + 1)) { ax_debug ("Combining less_signed & log_not & if_goto"); pc += 2; aentry->pc = pc; arg = aexpr->bytes[pc++]; arg = (arg << 8) + aexpr->bytes[pc++]; aentry->goto_pc = arg; emit_ge_goto (&(aentry->from_offset), &(aentry->from_size)); } else emit_less_signed (); break; case gdb_agent_op_less_unsigned: emit_less_unsigned (); break; case gdb_agent_op_ext: arg = aexpr->bytes[pc++]; if (arg < (sizeof (LONGEST) * 8)) emit_ext (arg); break; case gdb_agent_op_ref8: emit_ref (1); break; case gdb_agent_op_ref16: emit_ref (2); break; case gdb_agent_op_ref32: emit_ref (4); break; case gdb_agent_op_ref64: emit_ref (8); break; case gdb_agent_op_if_goto: arg = aexpr->bytes[pc++]; arg = (arg << 8) + aexpr->bytes[pc++]; aentry->goto_pc = arg; emit_if_goto (&(aentry->from_offset), &(aentry->from_size)); break; case gdb_agent_op_goto: arg = aexpr->bytes[pc++]; arg = (arg << 8) + aexpr->bytes[pc++]; aentry->goto_pc = arg; emit_goto (&(aentry->from_offset), &(aentry->from_size)); break; case gdb_agent_op_const8: emit_stack_flush (); top = aexpr->bytes[pc++]; emit_const (top); break; case gdb_agent_op_const16: emit_stack_flush (); top = aexpr->bytes[pc++]; top = (top << 8) + aexpr->bytes[pc++]; emit_const (top); break; case gdb_agent_op_const32: emit_stack_flush (); top = aexpr->bytes[pc++]; top = (top << 8) + aexpr->bytes[pc++]; top = (top << 8) + aexpr->bytes[pc++]; top = (top << 8) + aexpr->bytes[pc++]; emit_const (top); break; case gdb_agent_op_const64: emit_stack_flush (); top = aexpr->bytes[pc++]; top = (top << 8) + aexpr->bytes[pc++]; top = (top << 8) + aexpr->bytes[pc++]; top = (top << 8) + aexpr->bytes[pc++]; top = (top << 8) + aexpr->bytes[pc++]; top = (top << 8) + aexpr->bytes[pc++]; top = (top << 8) + aexpr->bytes[pc++]; top = (top << 8) + aexpr->bytes[pc++]; emit_const (top); break; case gdb_agent_op_reg: emit_stack_flush (); arg = aexpr->bytes[pc++]; arg = (arg << 8) + aexpr->bytes[pc++]; emit_reg (arg); break; case gdb_agent_op_end: ax_debug ("At end of expression\n"); /* Assume there is one stack element left, and that it is cached in "top" where emit_epilogue can get to it. */ emit_stack_adjust (1); done = 1; break; case gdb_agent_op_dup: /* In our design, dup is equivalent to stack flushing. */ emit_stack_flush (); break; case gdb_agent_op_pop: emit_pop (); break; case gdb_agent_op_zero_ext: arg = aexpr->bytes[pc++]; if (arg < (sizeof (LONGEST) * 8)) emit_zero_ext (arg); break; case gdb_agent_op_swap: next_op = aexpr->bytes[pc]; /* Detect greater-than comparison sequences. */ if (next_op == gdb_agent_op_less_signed && !is_goto_target (aexpr, pc) && (aexpr->bytes[pc + 1] == gdb_agent_op_if_goto) && !is_goto_target (aexpr, pc + 1)) { ax_debug ("Combining swap & less_signed & if_goto"); pc += 2; aentry->pc = pc; arg = aexpr->bytes[pc++]; arg = (arg << 8) + aexpr->bytes[pc++]; aentry->goto_pc = arg; emit_gt_goto (&(aentry->from_offset), &(aentry->from_size)); } else if (next_op == gdb_agent_op_less_signed && !is_goto_target (aexpr, pc) && (aexpr->bytes[pc + 1] == gdb_agent_op_log_not) && !is_goto_target (aexpr, pc + 1) && (aexpr->bytes[pc + 2] == gdb_agent_op_if_goto) && !is_goto_target (aexpr, pc + 2)) { ax_debug ("Combining swap & less_signed & log_not & if_goto"); pc += 3; aentry->pc = pc; arg = aexpr->bytes[pc++]; arg = (arg << 8) + aexpr->bytes[pc++]; aentry->goto_pc = arg; emit_le_goto (&(aentry->from_offset), &(aentry->from_size)); } else emit_swap (); break; case gdb_agent_op_getv: emit_stack_flush (); arg = aexpr->bytes[pc++]; arg = (arg << 8) + aexpr->bytes[pc++]; emit_int_call_1 (get_get_tsv_func_addr (), arg); break; case gdb_agent_op_setv: arg = aexpr->bytes[pc++]; arg = (arg << 8) + aexpr->bytes[pc++]; emit_void_call_2 (get_set_tsv_func_addr (), arg); break; case gdb_agent_op_tracev: UNHANDLED; break; /* GDB never (currently) generates any of these ops. */ case gdb_agent_op_float: case gdb_agent_op_ref_float: case gdb_agent_op_ref_double: case gdb_agent_op_ref_long_double: case gdb_agent_op_l_to_d: case gdb_agent_op_d_to_l: case gdb_agent_op_trace16: UNHANDLED; break; default: ax_debug ("Agent expression op 0x%x not recognized\n", op); /* Don't struggle on, things will just get worse. */ return expr_eval_unrecognized_opcode; } /* This catches errors that occur in target-specific code emission. */ if (emit_error) { ax_debug ("Error %d while emitting code for %s\n", emit_error, gdb_agent_op_name (op)); return expr_eval_unhandled_opcode; } ax_debug ("Op %s compiled\n", gdb_agent_op_name (op)); } /* Now fill in real addresses as goto destinations. */ for (aentry = bytecode_address_table; aentry; aentry = aentry->next) { int written = 0; if (aentry->goto_pc < 0) continue; /* Find the location that we are going to, and call back into target-specific code to write the actual address or displacement. */ for (aentry2 = bytecode_address_table; aentry2; aentry2 = aentry2->next) { if (aentry2->pc == aentry->goto_pc) { ax_debug ("Want to jump from %s to %s\n", paddress (aentry->address), paddress (aentry2->address)); write_goto_address (aentry->address + aentry->from_offset, aentry2->address, aentry->from_size); written = 1; break; } } /* Error out if we didn't find a destination. */ if (!written) { ax_debug ("Destination of goto %d not found\n", aentry->goto_pc); return expr_eval_invalid_goto; } } return expr_eval_no_error; }