< 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 >