. */ if (TREE_CODE (addr) != ADDR_EXPR || DECL_P (TREE_OPERAND (addr, 0))) return fold_build2 (MEM_REF, type, addr, wide_int_to_tree (ptype, off)); } /* *(foo *)fooarrptr => (*fooarrptr)[0] */ if (TREE_CODE (TREE_TYPE (subtype)) == ARRAY_TYPE && TREE_CODE (TYPE_SIZE (TREE_TYPE (TREE_TYPE (subtype)))) == INTEGER_CST && useless_type_conversion_p (type, TREE_TYPE (TREE_TYPE (subtype)))) { tree type_domain; tree min_val = size_zero_node; tree osub = sub; sub = gimple_fold_indirect_ref (sub); if (! sub) sub = build1 (INDIRECT_REF, TREE_TYPE (subtype), osub); type_domain = TYPE_DOMAIN (TREE_TYPE (sub)); if (type_domain && TYPE_MIN_VALUE (type_domain)) min_val = TYPE_MIN_VALUE (type_domain); if (TREE_CODE (min_val) == INTEGER_CST) return build4 (ARRAY_REF, type, sub, min_val, NULL_TREE, NULL_TREE); } return NULL_TREE; } /* Return true if CODE is an operation that when operating on signed integer types involves undefined behavior on overflow and the operation can be expressed with unsigned arithmetic. */ bool arith_code_with_undefined_signed_overflow (tree_code code) { switch (code) { case PLUS_EXPR: case MINUS_EXPR: case MULT_EXPR: case NEGATE_EXPR: case POINTER_PLUS_EXPR: return true; default: return false; } } /* Rewrite STMT, an assignment with a signed integer or pointer arithmetic operation that can be transformed to unsigned arithmetic by converting its operand, carrying out the operation in the corresponding unsigned type and converting the result back to the original type. Returns a sequence of statements that replace STMT and also contain a modified form of STMT itself. */ gimple_seq rewrite_to_defined_overflow (gimple stmt) { if (dump_file && (dump_flags & TDF_DETAILS)) { fprintf (dump_file, "rewriting stmt with undefined signed " "overflow "); print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM); } tree lhs = gimple_assign_lhs (stmt); tree type = unsigned_type_for (TREE_TYPE (lhs)); gimple_seq stmts = NULL; for (unsigned i = 1; i < gimple_num_ops (stmt); ++i) { gimple_seq stmts2 = NULL; gimple_set_op (stmt, i, force_gimple_operand (fold_convert (type, gimple_op (stmt, i)), &stmts2, true, NULL_TREE)); gimple_seq_add_seq (&stmts, stmts2); } gimple_assign_set_lhs (stmt, make_ssa_name (type, stmt)); if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR) gimple_assign_set_rhs_code (stmt, PLUS_EXPR); gimple_seq_add_stmt (&stmts, stmt); gimple cvt = gimple_build_assign (lhs, NOP_EXPR, gimple_assign_lhs (stmt)); gimple_seq_add_stmt (&stmts, cvt); return stmts; } /* The valueization hook we use for the gimple_build API simplification. This makes us match fold_buildN behavior by only combining with statements in the sequence(s) we are currently building. */ static tree gimple_build_valueize (tree op) { if (gimple_bb (SSA_NAME_DEF_STMT (op)) == NULL) return op; return NULL_TREE; } /* Build the expression CODE OP0 of type TYPE with location LOC, simplifying it first if possible. Returns the built expression value and appends statements possibly defining it to SEQ. */ tree gimple_build (gimple_seq *seq, location_t loc, enum tree_code code, tree type, tree op0) { tree res = gimple_simplify (code, type, op0, seq, gimple_build_valueize); if (!res) { if (gimple_in_ssa_p (cfun)) res = make_ssa_name (type); else res = create_tmp_reg (type); gimple stmt; if (code == REALPART_EXPR || code == IMAGPART_EXPR || code == VIEW_CONVERT_EXPR) stmt = gimple_build_assign (res, code, build1 (code, type, op0)); else stmt = gimple_build_assign (res, code, op0); gimple_set_location (stmt, loc); gimple_seq_add_stmt_without_update (seq, stmt); } return res; } /* Build the expression OP0 CODE OP1 of type TYPE with location LOC, simplifying it first if possible. Returns the built expression value and appends statements possibly defining it to SEQ. */ tree gimple_build (gimple_seq *seq, location_t loc, enum tree_code code, tree type, tree op0, tree op1) { tree res = gimple_simplify (code, type, op0, op1, seq, gimple_build_valueize); if (!res) { if (gimple_in_ssa_p (cfun)) res = make_ssa_name (type); else res = create_tmp_reg (type); gimple stmt = gimple_build_assign (res, code, op0, op1); gimple_set_location (stmt, loc); gimple_seq_add_stmt_without_update (seq, stmt); } return res; } /* Build the expression (CODE OP0 OP1 OP2) of type TYPE with location LOC, simplifying it first if possible. Returns the built expression value and appends statements possibly defining it to SEQ. */ tree gimple_build (gimple_seq *seq, location_t loc, enum tree_code code, tree type, tree op0, tree op1, tree op2) { tree res = gimple_simplify (code, type, op0, op1, op2, seq, gimple_build_valueize); if (!res) { if (gimple_in_ssa_p (cfun)) res = make_ssa_name (type); else res = create_tmp_reg (type); gimple stmt; if (code == BIT_FIELD_REF) stmt = gimple_build_assign (res, code, build3 (code, type, op0, op1, op2)); else stmt = gimple_build_assign (res, code, op0, op1, op2); gimple_set_location (stmt, loc); gimple_seq_add_stmt_without_update (seq, stmt); } return res; } /* Build the call FN (ARG0) with a result of type TYPE (or no result if TYPE is void) with location LOC, simplifying it first if possible. Returns the built expression value (or NULL_TREE if TYPE is void) and appends statements possibly defining it to SEQ. */ tree gimple_build (gimple_seq *seq, location_t loc, enum built_in_function fn, tree type, tree arg0) { tree res = gimple_simplify (fn, type, arg0, seq, gimple_build_valueize); if (!res) { tree decl = builtin_decl_implicit (fn); gimple stmt = gimple_build_call (decl, 1, arg0); if (!VOID_TYPE_P (type)) { if (gimple_in_ssa_p (cfun)) res = make_ssa_name (type); else res = create_tmp_reg (type); gimple_call_set_lhs (stmt, res); } gimple_set_location (stmt, loc); gimple_seq_add_stmt_without_update (seq, stmt); } return res; } /* Build the call FN (ARG0, ARG1) with a result of type TYPE (or no result if TYPE is void) with location LOC, simplifying it first if possible. Returns the built expression value (or NULL_TREE if TYPE is void) and appends statements possibly defining it to SEQ. */ tree gimple_build (gimple_seq *seq, location_t loc, enum built_in_function fn, tree type, tree arg0, tree arg1) { tree res = gimple_simplify (fn, type, arg0, arg1, seq, gimple_build_valueize); if (!res) { tree decl = builtin_decl_implicit (fn); gimple stmt = gimple_build_call (decl, 2, arg0, arg1); if (!VOID_TYPE_P (type)) { if (gimple_in_ssa_p (cfun)) res = make_ssa_name (type); else res = create_tmp_reg (type); gimple_call_set_lhs (stmt, res); } gimple_set_location (stmt, loc); gimple_seq_add_stmt_without_update (seq, stmt); } return res; } /* Build the call FN (ARG0, ARG1, ARG2) with a result of type TYPE (or no result if TYPE is void) with location LOC, simplifying it first if possible. Returns the built expression value (or NULL_TREE if TYPE is void) and appends statements possibly defining it to SEQ. */ tree gimple_build (gimple_seq *seq, location_t loc, enum built_in_function fn, tree type, tree arg0, tree arg1, tree arg2) { tree res = gimple_simplify (fn, type, arg0, arg1, arg2, seq, gimple_build_valueize); if (!res) { tree decl = builtin_decl_implicit (fn); gimple stmt = gimple_build_call (decl, 3, arg0, arg1, arg2); if (!VOID_TYPE_P (type)) { if (gimple_in_ssa_p (cfun)) res = make_ssa_name (type); else res = create_tmp_reg (type); gimple_call_set_lhs (stmt, res); } gimple_set_location (stmt, loc); gimple_seq_add_stmt_without_update (seq, stmt); } return res; } /* Build the conversion (TYPE) OP with a result of type TYPE with location LOC if such conversion is neccesary in GIMPLE, simplifying it first. Returns the built expression value and appends statements possibly defining it to SEQ. */ tree gimple_convert (gimple_seq *seq, location_t loc, tree type, tree op) { if (useless_type_conversion_p (type, TREE_TYPE (op))) return op; return gimple_build (seq, loc, NOP_EXPR, type, op); }