< prev index next >

src/cpu/sparc/vm/assembler_sparc.hpp

Print this page

        

@@ -463,10 +463,40 @@
   }
   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,97 +639,134 @@
 
   // 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
+#define VALIDATE_PIPELINE
 #endif
-#ifdef CHECK_DELAY
-  enum Delay_state { no_delay, at_delay_slot, filling_delay_slot } delay_state;
+
+#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:
-  // Tells assembler next instruction must NOT be in delay slot.
-  // Use at start of multinstruction macros.
+  // 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 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");
+    // 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
   }
-  void assert_not_delayed(const char* msg) {
-#ifdef CHECK_DELAY
-    assert(delay_state == no_delay, msg);
+
+ 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:
-  // Insert a nop if the previous is cbcond
-  inline void insert_nop_after_cbcond();
+  // 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();
 
-  // Delay slot helpers
-  // cti is called when emitting control-transfer instruction,
-  // BEFORE doing the emitting.
-  // Only effective when assertion-checking is enabled.
+  // 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 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");
+    // 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
-  void has_delay_slot() {
-#ifdef CHECK_DELAY
-    assert_not_delayed("just checking");
-    delay_state = at_delay_slot;
+  // 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
   }
 
-  // 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);
+  inline void induce_pc_hazard() {
+#ifdef VALIDATE_PIPELINE
+    assert_no_hazard();
+    _hazard_state = PcHazard;
+#endif
   }
 
-  void no_cbcond_before() {
-    assert(offset() == 0 || !cbcond_before(), "cbcond should not follow an other cbcond");
+  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.");
   }
-public:
 
+  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 || cbcond_before()) return false;
+    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 CHECK_DELAY
-    assert(delay_state == at_delay_slot, "delayed instruction is not in delay slot");
-    delay_state = filling_delay_slot;
+#ifdef VALIDATE_PIPELINE
+    assert(_delay_state == AtDelay, "Delayed instruction not in delay-slot.");
+    _delay_state = FillDelay;
 #endif
     return this;
   }
 
   void flush() {
-#ifdef CHECK_DELAY
-    assert(delay_state == no_delay, "ending code with a delay slot");
+#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,12 +1280,13 @@
 
   inline void crc32c(FloatRegister s1, FloatRegister s2, FloatRegister d);
 
   // Creation
   Assembler(CodeBuffer* code) : AbstractAssembler(code) {
-#ifdef CHECK_DELAY
-    delay_state = no_delay;
+#ifdef VALIDATE_PIPELINE
+    _delay_state  = NoDelay;
+    _hazard_state = NoHazard;
 #endif
   }
 };
 
 #endif // CPU_SPARC_VM_ASSEMBLER_SPARC_HPP
< prev index next >