+ tree base, expn;
+ enum tree_code bc, ec;
+ gcc_assert (TREE_CODE (pow_call) == CALL_EXPR);
+ gcc_assert (call_expr_nargs (pow_call) == 2);
+ gcc_assert (fnc == BUILT_IN_POW);
+
+ *nconds = 0;
+
+ base = CALL_EXPR_ARG (pow_call, 0);
+ expn = CALL_EXPR_ARG (pow_call, 1);
+
+ bc = TREE_CODE (base);
+ ec = TREE_CODE (expn);
+
+ gcc_assert (TREE_CODE_CLASS (bc) != tcc_constant ||
+ bc == REAL_CST);
+ gcc_assert (TREE_CODE_CLASS (ec) != tcc_constant ||
+ ec == REAL_CST);
+
+ if (bc == REAL_CST)
+ {
+ tree float_typ, max_exp_real_cst;
+ tree temp, tempn, tempc, tempcn, stmt1, stmt2, stmt3;
+ REAL_VALUE_TYPE mv;
+
+ /* See candidate selection in check_pow.
+ Since the candidates have a given range
+ of base values, the guard code generated
+ for such calls: pow(const,y) are simple:
+ if ( y > max_y )
+ pow(const, y);
+ max_y can be computed separately for each
+ const base, but in this implemetation, we
+ choose to compute it using the max base
+ in the allowed range. */
+
+ REAL_VALUE_TYPE bcv = TREE_REAL_CST (base);
+ gcc_assert (!REAL_VALUES_EQUAL (bcv, dconst1));
+ gcc_assert (!REAL_VALUES_LESS (bcv, dconst1));
+ real_from_integer (&mv, VOIDmode,256,0,1),
+ gcc_assert (!REAL_VALUES_LESS (mv, bcv));
+ float_typ = TREE_TYPE (expn);
+
+ max_exp_real_cst = build_real (float_typ, mv);
+ temp = create_tmp_var (float_typ, "DCE_COND");
+ stmt1 = build_gimple_modify_stmt (temp, expn);
+ tempn = make_ssa_name (temp, stmt1);
+ GIMPLE_STMT_OPERAND (stmt1, 0) = tempn;
+
+ tempc = create_tmp_var (boolean_type_node, "DCE_COND_TEST");
+ stmt2 = build_gimple_modify_stmt (tempc,
+ build2 (GT_EXPR,
+ boolean_type_node,
+ tempn, max_exp_real_cst));
+ tempcn = make_ssa_name (tempc, stmt2);
+ GIMPLE_STMT_OPERAND (stmt2, 0) = tempcn;
+
+ stmt3 = build3 (COND_EXPR, void_type_node,
+ tempcn, NULL_TREE, NULL_TREE);
+ VEC_safe_push (tree, heap, conds, stmt1);
+ VEC_safe_push (tree, heap, conds, stmt2);
+ VEC_safe_push (tree, heap, conds, stmt3);
+ (*nconds)++;
+
+ }
+ else if (bc == SSA_NAME)
+ {
+ tree def, nm, rhs, rhs0, var, int_typ, float_typ;
+ tree max_exp_cst, max_exp_real_cst;
+ tree temp1, temp1n, temp2, temp2n, temp2c, temp2cn;
+ tree cst0, stmt1, stmt2, stmt3;
+ int sz, max_exp;
+
+ /* Generate error condition code for pow calls with
+ non constant base value. The candidates selected
+ have their base argument value converted from
+ integer (see check_pow) value (1,2,4 bytes), and
+ the max exp value is computed based on the size
+ of the integer type. The code below first does
+ sanity check and then does code generation. */
+
+ def = SSA_NAME_DEF_STMT (base);
+ gcc_assert (TREE_CODE (def) == GIMPLE_MODIFY_STMT);
+
+ nm = GIMPLE_STMT_OPERAND (def,0);
+ gcc_assert (TREE_CODE (nm) == SSA_NAME);
+ gcc_assert (nm == base);
+
+ rhs = GIMPLE_STMT_OPERAND (def,1);
+
+ gcc_assert (TREE_CODE (rhs) == FLOAT_EXPR);
+ rhs0 = TREE_OPERAND (rhs,0);
+ gcc_assert (TREE_CODE (rhs0) == SSA_NAME);
+
+ var = SSA_NAME_VAR (rhs0);
+ gcc_assert (TREE_CODE (var) == VAR_DECL
+ || TREE_CODE (var) == PARM_DECL);
+
+ int_typ = TREE_TYPE (var);
+ gcc_assert (TREE_CODE (int_typ) == INTEGER_TYPE);
+
+ sz = int_size_in_bytes (int_typ);
+ gcc_assert (sz > 0 && sz <= INT_TYPE_SIZE) ;
+
+
+ float_typ = TREE_TYPE (SSA_NAME_VAR (expn));
+ if (sz == 1)
+ max_exp = 128;
+ else if (sz == 2)
+ max_exp = 64;
+ else
+ {
+ gcc_assert (sz == 4);
+ max_exp = 32;
+ }
+ max_exp_cst = build_int_cst (integer_type_node, max_exp);
+ max_exp_real_cst = build_real_from_int_cst (float_typ, max_exp_cst);
+
+ /* For pow ((dobule)x,y), generate the following conditions:
+ cond 1:
+ temp1 = x;
+ if (temp1 <= 0)
+
+ cond 2:
+ temp2 = y;
+ if (temp2 > max_exp_real_cst) */
+
+ temp2 = create_tmp_var (float_typ, "DCE_COND2");
+ stmt1 = build_gimple_modify_stmt (temp2, expn);
+ temp2n = make_ssa_name (temp2, stmt1);
+ GIMPLE_STMT_OPERAND (stmt1,0) = temp2n;
+
+ temp2c = create_tmp_var (boolean_type_node, "DCE_COND2_TEST");
+ stmt2 = build_gimple_modify_stmt (temp2c,
+ build2 (GT_EXPR,
+ boolean_type_node,
+ temp2n, max_exp_real_cst));
+ temp2cn = make_ssa_name (temp2c, stmt2);
+ GIMPLE_STMT_OPERAND (stmt2, 0) = temp2cn;
+
+ stmt3 = build3 (COND_EXPR, void_type_node,
+ temp2cn, NULL_TREE, NULL_TREE);
+ VEC_safe_push (tree, heap, conds, stmt1);
+ VEC_safe_push (tree, heap, conds, stmt2);
+ VEC_safe_push (tree, heap, conds, stmt3);
+ (*nconds)++;
+
+ /* Now a seperator*/
+ VEC_safe_push (tree, heap, conds, NULL);
+
+ temp1 = create_tmp_var (int_typ, "DCE_COND1");
+ cst0 = build_int_cst (int_typ, 0);
+ stmt1 = build_gimple_modify_stmt (temp1, rhs0);
+ temp1n = make_ssa_name (temp1, stmt1);
+ GIMPLE_STMT_OPERAND (stmt1,0) = temp1n;
+ stmt2 = build3 (COND_EXPR, void_type_node,
+ build2 (LE_EXPR, boolean_type_node, temp1n, cst0),
+ NULL_TREE, NULL_TREE);
+
+ VEC_safe_push (tree, heap, conds, stmt1);
+ VEC_safe_push (tree, heap, conds, stmt2);
+ (*nconds)++;
+
+ }
+ else
+ gcc_unreachable ();
+}