Bound operation added:
authorMichael Beck <beck@ipd.info.uni-karlsruhe.de>
Thu, 12 Jan 2006 01:00:21 +0000 (01:00 +0000)
committerMichael Beck <beck@ipd.info.uni-karlsruhe.de>
Thu, 12 Jan 2006 01:00:21 +0000 (01:00 +0000)
 high level bounds check for Java, Pascal, Modula-3

[r7214]

ir/ir/ircons.c
ir/ir/ircons.h
ir/ir/irdump.c
ir/ir/irnode.c
ir/ir/irnode.h
ir/ir/irnode_t.h
ir/ir/irop.c
ir/ir/irop.h
ir/ir/irvrfy.c

index 85d1ec0..085ee13 100644 (file)
@@ -964,6 +964,27 @@ new_bd_CopyB  (dbg_info *db, ir_node *block,
   return res;
 }
 
+static ir_node *
+new_bd_Bound (dbg_info *db, ir_node *block,
+    ir_node *store, ir_node *idx, ir_node *lower, ir_node *upper)
+{
+  ir_node  *in[4];
+  ir_node  *res;
+  ir_graph *irg = current_ir_graph;
+
+  in[0] = store;
+  in[1] = idx;
+  in[2] = lower;
+  in[3] = upper;
+
+  res = new_ir_node(db, irg, block, op_Bound, mode_T, 4, in);
+
+  res->attr.copyb.exc.pin_state = op_pin_state_pinned;
+  res = optimize_node(res);
+  IRN_VRFY_IRG(res, irg);
+  return res;
+}
+
 /* --------------------------------------------- */
 /* private interfaces, for professional use only */
 /* --------------------------------------------- */
@@ -1750,6 +1771,19 @@ ir_node *new_rd_CopyB(dbg_info *db, ir_graph *irg, ir_node *block,
   return res;
 }
 
+ir_node *new_rd_Bound(dbg_info *db, ir_graph *irg, ir_node *block,
+    ir_node *store, ir_node *idx, ir_node *lower, ir_node *upper)
+{
+  ir_node  *res;
+  ir_graph *rem = current_ir_graph;
+
+  current_ir_graph = irg;
+  res = new_bd_Bound(db, block, store, idx, lower, upper);
+  current_ir_graph = rem;
+
+  return res;
+}
+
 ir_node *new_r_Block  (ir_graph *irg,  int arity, ir_node **in) {
   return new_rd_Block(NULL, irg, arity, in);
 }
@@ -1959,11 +1993,14 @@ ir_node *new_r_Mux (ir_graph *irg, ir_node *block,
     ir_node *sel, ir_node *ir_false, ir_node *ir_true, ir_mode *mode) {
   return new_rd_Mux(NULL, irg, block, sel, ir_false, ir_true, mode);
 }
-
 ir_node *new_r_CopyB(ir_graph *irg, ir_node *block,
     ir_node *store, ir_node *dst, ir_node *src, type *data_type) {
   return new_rd_CopyB(NULL, irg, block, store, dst, src, data_type);
 }
+ir_node *new_r_Bound(ir_graph *irg, ir_node *block,
+    ir_node *store, ir_node *idx, ir_node *lower, ir_node *upper) {
+  return new_rd_Bound(NULL, irg, block, store, idx, lower, upper);
+}
 
 /** ********************/
 /** public interfaces  */
@@ -2591,7 +2628,7 @@ get_r_frag_value_internal (ir_node *block, ir_node *cfOp, int pos, ir_mode *mode
   }
   return res;
 }
-#endif
+#endif /* PRECISE_EXC_CONTEXT */
 
 /**
     computes the predecessors for the real phi node, and then
@@ -3311,6 +3348,17 @@ ir_node *new_d_CopyB(dbg_info *db,ir_node *store,
   return res;
 }
 
+ir_node *new_d_Bound(dbg_info *db,ir_node *store,
+    ir_node *idx, ir_node *lower, ir_node *upper) {
+  ir_node *res;
+  res = new_bd_Bound(db, current_ir_graph->current_block,
+    store, idx, lower, upper);
+#if PRECISE_EXC_CONTEXT
+  allocate_frag_arr(res, op_Bound, &res->attr.bound.exc.frag_arr);
+#endif
+  return res;
+}
+
 /* ********************************************************************* */
 /* Comfortable interface with automatic Phi node construction.           */
 /* (Uses also constructors of ?? interface, except new_Block.            */
@@ -3642,3 +3690,6 @@ ir_node *new_Mux (ir_node *sel, ir_node *ir_false, ir_node *ir_true, ir_mode *mo
 ir_node *new_CopyB(ir_node *store, ir_node *dst, ir_node *src, type *data_type) {
   return new_d_CopyB(NULL, store, dst, src, data_type);
 }
+ir_node *new_Bound(ir_node *store, ir_node *idx, ir_node *lower, ir_node *upper) {
+  return new_d_Bound(NULL, store, idx, lower, upper);
+}
index 1013878..38ae196 100644 (file)
  *    ir_node *new_NoMem  (void);
  *    ir_node *new_Mux    (ir_node *sel, ir_node *ir_false, ir_node *ir_true, ir_mode *mode);
  *    ir_node *new_CopyB  (ir_node *store, ir_node *dst, ir_node *src, type *data_type);
+ *    ir_node *new_Bound  (ir_node *store, ir_node *idx, ir_node *lower, ir_node *upper);
  *
  *    void add_immBlock_pred (ir_node *block, ir_node *jmp);
  *    void mature_immBlock (ir_node *block);
  *    Describes a high level block copy of a compound type form address src to
  *    address dst. Must be lowered to a Call to a runtime memory copy function.
  *
+ *    ir_node *new_Bound  (ir_node *store, ir_node *idx, ir_node *lower, ir_node *upper);
+ *    -----------------------------------------------------------------------------------
+ *
+ *    Describes a high level bounds check. Must be lowered to a Call to a runtime check
+ *    function.
+ *
  *    ir_node *new_Proj (ir_node *arg, ir_mode *mode, long proj)
  *    ----------------------------------------------------------
  *
@@ -1816,8 +1823,6 @@ ir_node *new_rd_Filter (dbg_info *db, ir_graph *irg, ir_node *block, ir_node *ar
 ir_node *new_rd_NoMem  (ir_graph *irg);
 
 /** Constructor for a Mux node.
- *
- * Adds the node to the block in current_ir_block.
  *
  * @param *db       A pointer for debug information.
  * @param *irg      The ir graph the node belong to.
@@ -1831,8 +1836,6 @@ ir_node *new_rd_Mux  (dbg_info *db, ir_graph *irg, ir_node *block,
     ir_node *sel, ir_node *ir_false, ir_node *ir_true, ir_mode *mode);
 
 /** Constructor for a CopyB node.
- *
- * Adds the node to the block in current_ir_block.
  *
  * @param *db         A pointer for debug information.
  * @param *irg        The ir graph the node belong to.
@@ -1845,6 +1848,20 @@ ir_node *new_rd_Mux  (dbg_info *db, ir_graph *irg, ir_node *block,
 ir_node *new_rd_CopyB(dbg_info *db, ir_graph *irg, ir_node *block,
     ir_node *store, ir_node *dst, ir_node *src, type *data_type);
 
+/** Constructor for a Bound node.
+ * Checks whether lower <= idx && idx < upper.
+ *
+ * @param *db         A pointer for debug information.
+ * @param *irg        The ir graph the node belong to.
+ * @param *block      The block the node belong to.
+ * @param *store      The current memory
+ * @param *idx        The ir_node that represents an index.
+ * @param *lower      The ir_node that represents the lower bound for the index.
+ * @param *upper      The ir_node that represents the upper bound for the index.
+ */
+ir_node *new_rd_Bound(dbg_info *db, ir_graph *irg, ir_node *block,
+    ir_node *store, ir_node *idx, ir_node *lower, ir_node *upper);
+
 /*-------------------------------------------------------------------------*/
 /* The raw interface without debug support                                 */
 /*-------------------------------------------------------------------------*/
@@ -2517,8 +2534,6 @@ ir_node *new_r_Filter (ir_graph *irg, ir_node *block, ir_node *arg,
 ir_node *new_r_NoMem  (ir_graph *irg);
 
 /** Constructor for a Mux node.
- *
- * Adds the node to the block in current_ir_block.
  *
  * @param *irg      The ir graph the node belong to.
  * @param *block    The block the node belong to.
@@ -2531,8 +2546,6 @@ ir_node *new_r_Mux  (ir_graph *irg, ir_node *block,
     ir_node *sel, ir_node *ir_false, ir_node *ir_true, ir_mode *mode);
 
 /** Constructor for a CopyB node.
- *
- * Adds the node to the block in current_ir_block.
  *
  * @param *irg        The ir graph the node belong to.
  * @param *block      The block the node belong to.
@@ -2544,6 +2557,19 @@ ir_node *new_r_Mux  (ir_graph *irg, ir_node *block,
 ir_node *new_r_CopyB(ir_graph *irg, ir_node *block,
     ir_node *store, ir_node *dst, ir_node *src, type *data_type);
 
+/** Constructor for a Bound node.
+ * Checks whether lower <= idx && idx < upper.
+ *
+ * @param *irg        The ir graph the node belong to.
+ * @param *block      The block the node belong to.
+ * @param *store      The current memory
+ * @param *idx        The ir_node that represents an index.
+ * @param *lower      The ir_node that represents the lower bound for the index.
+ * @param *upper      The ir_node that represents the upper bound for the index.
+ */
+ir_node *new_r_Bound(ir_graph *irg, ir_node *block,
+    ir_node *store, ir_node *idx, ir_node *lower, ir_node *upper);
+
 /*-----------------------------------------------------------------------*/
 /* The block oriented interface                                          */
 /*-----------------------------------------------------------------------*/
@@ -3233,8 +3259,6 @@ ir_node *new_d_Filter (dbg_info *db, ir_node *arg, ir_mode *mode, long proj);
 ir_node *new_d_NoMem  (void);
 
 /** Constructor for a Mux node.
- *
- * Adds the node to the block in current_ir_block.
  *
  * @param *db       A pointer for debug information.
  * @param *sel      The ir_node that calculates the boolean select.
@@ -3246,8 +3270,6 @@ ir_node *new_d_Mux  (dbg_info *db, ir_node *sel,
     ir_node *ir_false, ir_node *ir_true, ir_mode *mode);
 
 /** Constructor for a CopyB node.
- *
- * Adds the node to the block in current_ir_block.
  *
  * @param *db         A pointer for debug information.
  * @param *store      The current memory
@@ -3257,6 +3279,17 @@ ir_node *new_d_Mux  (dbg_info *db, ir_node *sel,
  */
 ir_node *new_d_CopyB(dbg_info *db, ir_node *store, ir_node *dst, ir_node *src, type *data_type);
 
+/** Constructor for a Bound node.
+ * Checks whether lower <= idx && idx < upper.
+ *
+ * @param *db         A pointer for debug information.
+ * @param *store      The current memory
+ * @param *idx        The ir_node that represents an index.
+ * @param *lower      The ir_node that represents the lower bound for the index.
+ * @param *upper      The ir_node that represents the upper bound for the index.
+ */
+ir_node *new_d_Bound(dbg_info *db, ir_node *store, ir_node *idx, ir_node *lower, ir_node *upper);
+
 /*-----------------------------------------------------------------------*/
 /* The block oriented interface without debug support                    */
 /*-----------------------------------------------------------------------*/
@@ -3869,6 +3902,18 @@ ir_node *new_Mux  (ir_node *sel, ir_node *ir_false, ir_node *ir_true, ir_mode *m
  */
 ir_node *new_CopyB(ir_node *store, ir_node *dst, ir_node *src, type *data_type);
 
+/** Constructor for a Bound node.
+ * Checks whether lower <= idx && idx < upper.
+ *
+ * Adds the node to the block in current_ir_block.
+ *
+ * @param *store      The current memory
+ * @param *idx        The ir_node that represents an index.
+ * @param *lower      The ir_node that represents the lower bound for the index.
+ * @param *upper      The ir_node that represents the upper bound for the index.
+ */
+ir_node *new_Bound(ir_node *store, ir_node *idx, ir_node *lower, ir_node *upper);
+
 /*---------------------------------------------------------------------*/
 /* The comfortable interface.                                          */
 /* Supports automatic Phi node construction.                           */
index b8ee522..31030bf 100644 (file)
@@ -858,6 +858,24 @@ static const pns_lookup_t alloc_lut[] = {
 #undef X
 };
 
+/** the lookup table for Proj(CopyB) names */
+static const pns_lookup_t copyb_lut[] = {
+#define X(a)    { pn_CopyB_##a, #a }
+  X(M),
+  X(X_except),
+  X(M_except)
+#undef X
+};
+
+/** the lookup table for Proj(Bound) names */
+static const pns_lookup_t bound_lut[] = {
+#define X(a)    { pn_Bound_##a, #a }
+  X(M),
+  X(X_except),
+  X(res),
+  X(M_except)
+#undef X
+};
 
 /** the Proj lookup table */
 static const proj_lookup_t proj_lut[] = {
@@ -871,7 +889,9 @@ static const proj_lookup_t proj_lut[] = {
   { iro_Mod,     E(mod_lut) },
   { iro_Load,    E(load_lut) },
   { iro_Store,   E(store_lut) },
-  { iro_Alloc,   E(alloc_lut) }
+  { iro_Alloc,   E(alloc_lut) },
+  { iro_CopyB,   E(copyb_lut) },
+  { iro_Bound,   E(bound_lut) }
 #undef E
 };
 
index d2ed264..fca414d 100644 (file)
@@ -2076,7 +2076,53 @@ void     set_CopyB_type(ir_node *node, ir_type *data_type) {
   node->attr.copyb.data_type = data_type;
 }
 
+/* Bound support */
 
+/* Returns the memory input of a Bound operation. */
+ir_node *get_Bound_mem(ir_node *bound) {
+  assert (bound->op == op_Bound);
+  return get_irn_n(bound, 0);
+}
+
+void     set_Bound_mem (ir_node *bound, ir_node *mem) {
+  assert (bound->op == op_Bound);
+  set_irn_n(bound, 0, mem);
+}
+
+/* Returns the index input of a Bound operation. */
+ir_node *get_Bound_index(ir_node *bound) {
+  assert (bound->op == op_Bound);
+  return get_irn_n(bound, 1);
+}
+
+void     set_Bound_index(ir_node *bound, ir_node *idx) {
+  assert (bound->op == op_Bound);
+  set_irn_n(bound, 1, idx);
+}
+
+/* Returns the lower bound input of a Bound operation. */
+ir_node *get_Bound_lower(ir_node *bound) {
+  assert (bound->op == op_Bound);
+  return get_irn_n(bound, 2);
+}
+
+void     set_Bound_lower(ir_node *bound, ir_node *lower) {
+  assert (bound->op == op_Bound);
+  set_irn_n(bound, 2, lower);
+}
+
+/* Returns the upper bound input of a Bound operation. */
+ir_node *get_Bound_upper(ir_node *bound) {
+  assert (bound->op == op_Bound);
+  return get_irn_n(bound, 3);
+}
+
+void     set_Bound_upper(ir_node *bound, ir_node *upper) {
+  assert (bound->op == op_Bound);
+  set_irn_n(bound, 3, upper);
+}
+
+/* returns the graph of a node */
 ir_graph *
 get_irn_irg(const ir_node *node) {
        /*
index a3b4412..469910a 100644 (file)
@@ -958,6 +958,35 @@ void     set_CopyB_src (ir_node *node, ir_node *src);
 ir_type *get_CopyB_type(ir_node *node);
 void     set_CopyB_type(ir_node *node, ir_type *data_type);
 
+/**
+ * Projection numbers for result of Bound node: use for Proj nodes!
+ */
+typedef enum {
+  pn_Bound_M_regular = 0,   /**< The memory result. */
+  pn_Bound_X_except = 1,    /**< The control flow result branching to the exception handler */
+  pn_Bound_res = 2,         /**< The checked index. */
+  pn_Bound_M_except = 3,    /**< The memory result in case the runtime function terminated with
+                                 an exception */
+  pn_Bound_max = 4          /**< number of projections from a Bound */
+} pn_Bound;
+#define pn_Bound_M pn_Bound_M_regular
+
+/** Returns the memory input of a Bound operation. */
+ir_node *get_Bound_mem(ir_node *bound);
+void     set_Bound_mem (ir_node *bound, ir_node *mem);
+
+/** Returns the index input of a Bound operation. */
+ir_node *get_Bound_index(ir_node *bound);
+void     set_Bound_index(ir_node *bound, ir_node *idx);
+
+/** Returns the lower bound input of a Bound operation. */
+ir_node *get_Bound_lower(ir_node *bound);
+void     set_Bound_lower(ir_node *bound, ir_node *lower);
+
+/** Returns the upper bound input of a Bound operation. */
+ir_node *get_Bound_upper(ir_node *bound);
+void     set_Bound_upper(ir_node *bound, ir_node *upper);
+
 /*
  *
  * NAME Auxiliary routines
index 6a3f03e..699d0b0 100644 (file)
@@ -181,6 +181,11 @@ typedef struct {
   ir_type        *data_type;    /**< type of the copied entity */
 } copyb_attr;
 
+/** Bound attribute */
+typedef struct {
+  except_attr    exc;           /**< the exception attribute. MUST be the first one. */
+} bound_attr;
+
 /**
  * Edge info to put into an irn.
  */
@@ -222,6 +227,7 @@ typedef union {
   end_attr       end;           /**< For EndReg, EndExcept */
   except_attr    except;        /**< For Phi node construction in case of exceptions */
   copyb_attr     copyb;         /**< For CopyB operation */
+  bound_attr     bound;         /**< For Bound operation */
 } attr;
 
 
index 23e9d89..14654a4 100644 (file)
@@ -93,6 +93,7 @@ ir_op *op_EndExcept;   ir_op *get_op_EndExcept (void) { return op_EndExcept; }
 ir_op *op_NoMem;       ir_op *get_op_NoMem     (void) { return op_NoMem;     }
 ir_op *op_Mux;         ir_op *get_op_Mux       (void) { return op_Mux;       }
 ir_op *op_CopyB;       ir_op *get_op_CopyB     (void) { return op_CopyB;     }
+ir_op *op_Bound;       ir_op *get_op_Bound     (void) { return op_Bound;     }
 
 
 /*
@@ -265,6 +266,7 @@ init_op(void)
   op_NoMem     = new_ir_op(iro_NoMem,     "NoMem",     op_pin_state_pinned, N,       oparity_zero,     -1, 0, NULL);
   op_Mux       = new_ir_op(iro_Mux,       "Mux",       op_pin_state_floats, N,       oparity_trinary,  -1, 0, NULL);
   op_CopyB     = new_ir_op(iro_CopyB,     "CopyB",   op_pin_state_mem_pinned, L|F|H, oparity_trinary,  -1, sizeof(copyb_attr), NULL);
+  op_Bound     = new_ir_op(iro_Bound,     "Bound",   op_pin_state_mem_pinned, L|F|H, oparity_trinary,  -1, sizeof(bound_attr), NULL);
 
 #undef H
 #undef Y
@@ -339,6 +341,7 @@ void finish_op(void) {
   free_ir_op (op_NoMem    ); op_NoMem     = NULL;
   free_ir_op (op_Mux      ); op_Mux       = NULL;
   free_ir_op (op_CopyB    ); op_CopyB     = NULL;
+  free_ir_op (op_Bound    ); op_Bound     = NULL;
 }
 
 /* Returns the string for the opcode. */
index ac8eeaa..c5471df 100644 (file)
@@ -74,7 +74,7 @@ typedef enum {
   iro_Load, iro_Store, iro_Alloc, iro_Free, iro_Sync,
   iro_Proj, iro_Tuple, iro_Id, iro_Bad, iro_Confirm,
   iro_Unknown, iro_Filter, iro_Break, iro_CallBegin, iro_EndReg, iro_EndExcept,
-  iro_NoMem, iro_Mux, iro_CopyB,
+  iro_NoMem, iro_Mux, iro_CopyB, iro_Bound,
   iro_MaxOpcode
 } opcode;
 
@@ -142,6 +142,7 @@ extern ir_op *op_EndExcept;       ir_op *get_op_EndExcept (void);
 extern ir_op *op_NoMem;           ir_op *get_op_NoMem     (void);
 extern ir_op *op_Mux;             ir_op *get_op_Mux       (void);
 extern ir_op *op_CopyB;           ir_op *get_op_CopyB     (void);
+extern ir_op *op_Bound;           ir_op *get_op_Bound     (void);
 
 /** Returns the ident for the opcode name */
 ident *get_op_ident(const ir_op *op);
index f5a6e95..d366cf6 100644 (file)
@@ -693,6 +693,47 @@ static int verify_node_Proj_EndExcept(ir_node *n, ir_node *p) {
   return 1;
 }
 
+/**
+ * verify a Proj(CopyB) node
+ */
+static int verify_node_Proj_CopyB(ir_node *n, ir_node *p) {
+  ir_mode *mode = get_irn_mode(p);
+  long proj     = get_Proj_proj(p);
+
+  ASSERT_AND_RET_DBG(
+    ((proj == pn_CopyB_M        && mode == mode_M) ||
+     (proj == pn_CopyB_X_except && mode == mode_X)),
+    "wrong Proj from CopyB", 0,
+    show_proj_failure(p);
+  );
+  if (proj == pn_CopyB_X_except)
+    ASSERT_AND_RET(
+      get_irn_pinned(n) == op_pin_state_pinned,
+      "Exception Proj from unpinned CopyB", 0);
+  return 1;
+}
+
+/**
+ * verify a Proj(Bound) node
+ */
+static int verify_node_Proj_Bound(ir_node *n, ir_node *p) {
+  ir_mode *mode = get_irn_mode(p);
+  long proj     = get_Proj_proj(p);
+
+  ASSERT_AND_RET_DBG(
+    ((proj == pn_Bound_M        && mode == mode_M) ||
+     (proj == pn_Bound_X_except && mode == mode_X) ||
+     (proj == pn_Bound_res      && mode == get_irn_mode(get_Bound_index(n)))),
+    "wrong Proj from Bound", 0,
+    show_proj_failure(p);
+  );
+  if (proj == pn_Bound_X_except)
+    ASSERT_AND_RET(
+      get_irn_pinned(n) == op_pin_state_pinned,
+      "Exception Proj from unpinned Bound", 0);
+  return 1;
+}
+
 /**
  * verify a Proj node
  */
@@ -1581,6 +1622,34 @@ static int verify_node_CopyB(ir_node *n, ir_graph *irg) {
   return 1;
 }
 
+/**
+ * verify a Bound node
+ */
+static int verify_node_Bound(ir_node *n, ir_graph *irg) {
+  ir_mode *mymode  = get_irn_mode(n);
+  ir_mode *op1mode = get_irn_mode(get_Bound_mem(n));
+  ir_mode *op2mode = get_irn_mode(get_Bound_index(n));
+  ir_mode *op3mode = get_irn_mode(get_Bound_lower(n));
+  ir_mode *op4mode = get_irn_mode(get_Bound_upper(n));
+
+  /* Bound: BB x M x ref x ref --> M x X */
+  ASSERT_AND_RET(
+    mymode == mode_T &&
+    op1mode == mode_M &&
+    op2mode == op3mode &&
+    op3mode == op4mode &&
+    mode_is_int(op3mode),
+    "Bound node", 0 );  /* operand M x int x int x int */
+
+  /* NoMem nodes are only allowed as memory input if the Bound is NOT pinned.
+     This should happen RARELY, as Bound COPIES MEMORY */
+  ASSERT_AND_RET(
+    (get_irn_op(get_Bound_mem(n)) == op_NoMem) ||
+    (get_irn_op(get_Bound_mem(n)) != op_NoMem && get_irn_pinned(n) == op_pin_state_pinned),
+    "Bound node with wrong memory input", 0 );
+  return 1;
+}
+
 /*
  * Check dominance.
  * For each usage of a node, it is checked, if the block of the
@@ -1928,6 +1997,7 @@ void firm_set_default_verifyer(opcode code, ir_op_ops *ops)
    CASE(Confirm);
    CASE(Mux);
    CASE(CopyB);
+   CASE(Bound);
    default:
      /* leave NULL */;
    }
@@ -1957,6 +2027,8 @@ void firm_set_default_verifyer(opcode code, ir_op_ops *ops)
    CASE(CallBegin);
    CASE(EndReg);
    CASE(EndExcept);
+   CASE(CopyB);
+   CASE(Bound);
    default:
      /* leave NULL */;
    }