< prev index next >
src/cpu/sparc/vm/assembler_sparc.hpp
Print this page
*** 463,472 ****
--- 463,502 ----
}
static bool is_cxb(int x) {
assert(is_cbcond(x), "wrong instruction");
return (x & (1 << 21)) != 0;
}
+ static bool is_branch(int x) {
+ if (inv_op(x) != Assembler::branch_op) return false;
+
+ bool is_bpr = inv_op2(x) == Assembler::bpr_op2;
+ bool is_bp = inv_op2(x) == Assembler::bp_op2;
+ bool is_br = inv_op2(x) == Assembler::br_op2;
+ bool is_fp = inv_op2(x) == Assembler::fb_op2;
+ bool is_fbp = inv_op2(x) == Assembler::fbp_op2;
+
+ return is_bpr || is_bp || is_br || is_fp || is_fbp;
+ }
+ static bool is_call(int x) {
+ return inv_op(x) == Assembler::call_op;
+ }
+ static bool is_jump(int x) {
+ if (inv_op(x) != Assembler::arith_op) return false;
+
+ bool is_jmpl = inv_op3(x) == Assembler::jmpl_op3;
+ bool is_rett = inv_op3(x) == Assembler::rett_op3;
+
+ return is_jmpl || is_rett;
+ }
+ static bool is_rdpc(int x) {
+ return (inv_op(x) == Assembler::arith_op && inv_op3(x) == Assembler::rdreg_op3 &&
+ inv_u_field(x, 18, 14) == 5);
+ }
+ static bool is_cti(int x) {
+ return is_branch(x) || is_call(x) || is_jump(x); // Ignoring done/retry
+ }
+
static int cond_cbcond(int x) { return u_field((((x & 8) << 1) + 8 + (x & 7)), 29, 25); }
static int inv_cond_cbcond(int x) {
assert(is_cbcond(x), "wrong instruction");
return inv_u_field(x, 27, 25) | (inv_u_field(x, 29, 29) << 3);
}
*** 609,705 ****
// instruction deprecated in v9
static void v9_dep() { } // do nothing for now
protected:
- // Simple delay-slot scheme:
- // In order to check the programmer, the assembler keeps track of delay slots.
- // It forbids CTIs in delay slots (conservative, but should be OK).
- // Also, when putting an instruction into a delay slot, you must say
- // asm->delayed()->add(...), in order to check that you don't omit
- // delay-slot instructions.
- // To implement this, we use a simple FSA
-
#ifdef ASSERT
! #define CHECK_DELAY
#endif
! #ifdef CHECK_DELAY
! enum Delay_state { no_delay, at_delay_slot, filling_delay_slot } delay_state;
#endif
public:
! // Tells assembler next instruction must NOT be in delay slot.
! // Use at start of multinstruction macros.
void assert_not_delayed() {
! // This is a separate overloading to avoid creation of string constants
! // in non-asserted code--with some compilers this pollutes the object code.
! #ifdef CHECK_DELAY
! assert_not_delayed("next instruction should not be a delay slot");
#endif
}
! void assert_not_delayed(const char* msg) {
! #ifdef CHECK_DELAY
! assert(delay_state == no_delay, msg);
#endif
}
protected:
! // Insert a nop if the previous is cbcond
! inline void insert_nop_after_cbcond();
! // Delay slot helpers
! // cti is called when emitting control-transfer instruction,
! // BEFORE doing the emitting.
! // Only effective when assertion-checking is enabled.
void cti() {
! // A cbcond instruction immediately followed by a CTI
! // instruction introduces pipeline stalls, we need to avoid that.
! no_cbcond_before();
! #ifdef CHECK_DELAY
! assert_not_delayed("cti should not be in delay slot");
#endif
}
! // called when emitting cti with a delay slot, AFTER emitting
! void has_delay_slot() {
! #ifdef CHECK_DELAY
! assert_not_delayed("just checking");
! delay_state = at_delay_slot;
#endif
}
! // cbcond instruction should not be generated one after an other
! bool cbcond_before() {
! if (offset() == 0) return false; // it is first instruction
! int x = *(int*)(intptr_t(pc()) - 4); // previous instruction
! return is_cbcond(x);
}
! void no_cbcond_before() {
! assert(offset() == 0 || !cbcond_before(), "cbcond should not follow an other cbcond");
}
- public:
bool use_cbcond(Label &L) {
! if (!UseCBCond || cbcond_before()) return false;
intptr_t x = intptr_t(target_distance(L)) - intptr_t(pc());
assert((x & 3) == 0, "not word aligned");
return is_simm12(x);
}
// Tells assembler you know that next instruction is delayed
Assembler* delayed() {
! #ifdef CHECK_DELAY
! assert(delay_state == at_delay_slot, "delayed instruction is not in delay slot");
! delay_state = filling_delay_slot;
#endif
return this;
}
void flush() {
! #ifdef CHECK_DELAY
! assert(delay_state == no_delay, "ending code with a delay slot");
#endif
AbstractAssembler::flush();
}
inline void emit_int32(int); // shadows AbstractAssembler::emit_int32
--- 639,772 ----
// instruction deprecated in v9
static void v9_dep() { } // do nothing for now
protected:
#ifdef ASSERT
! #define VALIDATE_PIPELINE
#endif
!
! #ifdef VALIDATE_PIPELINE
! // A simple delay-slot scheme:
! // In order to check the programmer, the assembler keeps track of delay-slots.
! // It forbids CTIs in delay-slots (conservative, but should be OK). Also, when
! // emitting an instruction into a delay-slot, you must do so using delayed(),
! // e.g. asm->delayed()->add(...), in order to check that you do not omit the
! // delay-slot instruction. To implement this, we use a simple FSA.
! enum { NoDelay, AtDelay, FillDelay } _delay_state;
!
! // A simple hazard scheme:
! // In order to avoid pipeline stalls, due to single cycle pipeline hazards, we
! // adopt a simplistic state tracking mechanism that will enforce an additional
! // 'nop' instruction to be inserted prior to emitting an instruction that can
! // expose a given hazard (currently, PC-related hazards only).
! enum { NoHazard, PcHazard } _hazard_state;
#endif
public:
! // Tell the assembler that the next instruction must NOT be in delay-slot.
! // Use at start of multi-instruction macros.
void assert_not_delayed() {
! // This is a separate entry to avoid the creation of string constants in
! // non-asserted code, with some compilers this pollutes the object code.
! #ifdef VALIDATE_PIPELINE
! assert_no_delay("Next instruction should not be in a delay-slot.");
#endif
}
!
! protected:
! void assert_no_delay(const char* msg) {
! #ifdef VALIDATE_PIPELINE
! assert(_delay_state == NoDelay, msg);
#endif
}
+ void assert_no_hazard() {
+ #ifdef VALIDATE_PIPELINE
+ assert(_hazard_state == NoHazard, "Unsolicited pipeline hazard.");
+ #endif
+ }
+
+ private:
+ inline int32_t prev_insn() {
+ assert(offset() > 0, "Interface violation.");
+ int32_t* addr = (int32_t*)pc() - 1;
+ return *addr;
+ }
+
+ #ifdef VALIDATE_PIPELINE
+ void validate_no_pipeline_hazards();
+ #endif
+
protected:
! // Avoid possible pipeline stall by inserting an additional 'nop' instruction,
! // if the previous instruction is a 'cbcond' or a 'rdpc'.
! inline void avoid_pipeline_stall();
! // A call to cti() is made before emitting a control-transfer instruction (CTI)
! // in order to assert a CTI is not emitted right after a 'cbcond', nor in the
! // delay-slot of another CTI. Only effective when assertions are enabled.
void cti() {
! // A 'cbcond' or 'rdpc' instruction immediately followed by a CTI introduces
! // a pipeline stall, which we make sure to prohibit.
! assert_no_cbcond_before();
! assert_no_rdpc_before();
! #ifdef VALIDATE_PIPELINE
! assert_no_hazard();
! assert_no_delay("CTI in delay-slot.");
#endif
}
! // Called when emitting CTI with a delay-slot, AFTER emitting.
! inline void induce_delay_slot() {
! #ifdef VALIDATE_PIPELINE
! assert_no_delay("Already in delay-slot.");
! _delay_state = AtDelay;
#endif
}
! inline void induce_pc_hazard() {
! #ifdef VALIDATE_PIPELINE
! assert_no_hazard();
! _hazard_state = PcHazard;
! #endif
}
! bool is_cbcond_before() { return offset() > 0 ? is_cbcond(prev_insn()) : false; }
!
! bool is_rdpc_before() { return offset() > 0 ? is_rdpc(prev_insn()) : false; }
!
! void assert_no_cbcond_before() {
! assert(offset() == 0 || !is_cbcond_before(), "CBCOND should not be followed by CTI.");
}
+ void assert_no_rdpc_before() {
+ assert(offset() == 0 || !is_rdpc_before(), "RDPC should not be followed by CTI.");
+ }
+
+ public:
+
bool use_cbcond(Label &L) {
! if (!UseCBCond || is_cbcond_before()) return false;
intptr_t x = intptr_t(target_distance(L)) - intptr_t(pc());
assert((x & 3) == 0, "not word aligned");
return is_simm12(x);
}
// Tells assembler you know that next instruction is delayed
Assembler* delayed() {
! #ifdef VALIDATE_PIPELINE
! assert(_delay_state == AtDelay, "Delayed instruction not in delay-slot.");
! _delay_state = FillDelay;
#endif
return this;
}
void flush() {
! #ifdef VALIDATE_PIPELINE
! assert(_delay_state == NoDelay, "Ending code with a delay-slot.");
! validate_no_pipeline_hazards();
#endif
AbstractAssembler::flush();
}
inline void emit_int32(int); // shadows AbstractAssembler::emit_int32
*** 1213,1224 ****
inline void crc32c(FloatRegister s1, FloatRegister s2, FloatRegister d);
// Creation
Assembler(CodeBuffer* code) : AbstractAssembler(code) {
! #ifdef CHECK_DELAY
! delay_state = no_delay;
#endif
}
};
#endif // CPU_SPARC_VM_ASSEMBLER_SPARC_HPP
--- 1280,1292 ----
inline void crc32c(FloatRegister s1, FloatRegister s2, FloatRegister d);
// Creation
Assembler(CodeBuffer* code) : AbstractAssembler(code) {
! #ifdef VALIDATE_PIPELINE
! _delay_state = NoDelay;
! _hazard_state = NoHazard;
#endif
}
};
#endif // CPU_SPARC_VM_ASSEMBLER_SPARC_HPP
< prev index next >