diff options
Diffstat (limited to 'gcc/expr.c')
-rw-r--r-- | gcc/expr.c | 120 |
1 files changed, 90 insertions, 30 deletions
@@ -142,7 +142,7 @@ static void store_constructor_field (rtx, unsigned HOST_WIDE_INT, tree, tree, int, int); static void store_constructor (tree, rtx, int, HOST_WIDE_INT); static rtx store_field (rtx, HOST_WIDE_INT, HOST_WIDE_INT, enum machine_mode, - tree, tree, int); + tree, tree, int, bool); static unsigned HOST_WIDE_INT highest_pow2_factor_for_target (tree, tree); @@ -4074,10 +4074,11 @@ optimize_bitfield_assignment_op (unsigned HOST_WIDE_INT bitsize, } -/* Expand an assignment that stores the value of FROM into TO. */ +/* Expand an assignment that stores the value of FROM into TO. If NONTEMPORAL + is true, try generating a nontemporal store. */ void -expand_assignment (tree to, tree from) +expand_assignment (tree to, tree from, bool nontemporal) { rtx to_rtx = 0; rtx result; @@ -4164,12 +4165,13 @@ expand_assignment (tree to, tree from) if (TREE_CODE (TREE_TYPE (from)) == COMPLEX_TYPE) { gcc_assert (bitpos == 0); - result = store_expr (from, to_rtx, false); + result = store_expr (from, to_rtx, false, nontemporal); } else { gcc_assert (bitpos == 0 || bitpos == GET_MODE_BITSIZE (mode1)); - result = store_expr (from, XEXP (to_rtx, bitpos != 0), false); + result = store_expr (from, XEXP (to_rtx, bitpos != 0), false, + nontemporal); } } else @@ -4195,7 +4197,8 @@ expand_assignment (tree to, tree from) result = NULL; else result = store_field (to_rtx, bitsize, bitpos, mode1, from, - TREE_TYPE (tem), get_alias_set (to)); + TREE_TYPE (tem), get_alias_set (to), + nontemporal); } if (result) @@ -4302,13 +4305,46 @@ expand_assignment (tree to, tree from) /* Compute FROM and store the value in the rtx we got. */ push_temp_slots (); - result = store_expr (from, to_rtx, 0); + result = store_expr (from, to_rtx, 0, nontemporal); preserve_temp_slots (result); free_temp_slots (); pop_temp_slots (); return; } +/* Emits nontemporal store insn that moves FROM to TO. Returns true if this + succeeded, false otherwise. */ + +static bool +emit_storent_insn (rtx to, rtx from) +{ + enum machine_mode mode = GET_MODE (to), imode; + enum insn_code code = storent_optab->handlers[mode].insn_code; + rtx pattern; + + if (code == CODE_FOR_nothing) + return false; + + imode = insn_data[code].operand[0].mode; + if (!insn_data[code].operand[0].predicate (to, imode)) + return false; + + imode = insn_data[code].operand[1].mode; + if (!insn_data[code].operand[1].predicate (from, imode)) + { + from = copy_to_mode_reg (imode, from); + if (!insn_data[code].operand[1].predicate (from, imode)) + return false; + } + + pattern = GEN_FCN (code) (to, from); + if (pattern == NULL_RTX) + return false; + + emit_insn (pattern); + return true; +} + /* Generate code for computing expression EXP, and storing the value into TARGET. @@ -4320,10 +4356,12 @@ expand_assignment (tree to, tree from) be more thorough? If CALL_PARAM_P is nonzero, this is a store into a call param on the - stack, and block moves may need to be treated specially. */ + stack, and block moves may need to be treated specially. + + If NONTEMPORAL is true, try using a nontemporal store instruction. */ rtx -store_expr (tree exp, rtx target, int call_param_p) +store_expr (tree exp, rtx target, int call_param_p, bool nontemporal) { rtx temp; rtx alt_rtl = NULL_RTX; @@ -4344,7 +4382,8 @@ store_expr (tree exp, rtx target, int call_param_p) part. */ expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, call_param_p ? EXPAND_STACK_PARM : EXPAND_NORMAL); - return store_expr (TREE_OPERAND (exp, 1), target, call_param_p); + return store_expr (TREE_OPERAND (exp, 1), target, call_param_p, + nontemporal); } else if (TREE_CODE (exp) == COND_EXPR && GET_MODE (target) == BLKmode) { @@ -4358,11 +4397,13 @@ store_expr (tree exp, rtx target, int call_param_p) do_pending_stack_adjust (); NO_DEFER_POP; jumpifnot (TREE_OPERAND (exp, 0), lab1); - store_expr (TREE_OPERAND (exp, 1), target, call_param_p); + store_expr (TREE_OPERAND (exp, 1), target, call_param_p, + nontemporal); emit_jump_insn (gen_jump (lab2)); emit_barrier (); emit_label (lab1); - store_expr (TREE_OPERAND (exp, 2), target, call_param_p); + store_expr (TREE_OPERAND (exp, 2), target, call_param_p, + nontemporal); emit_label (lab2); OK_DEFER_POP; @@ -4433,7 +4474,12 @@ store_expr (tree exp, rtx target, int call_param_p) } else { - temp = expand_expr_real (exp, target, GET_MODE (target), + rtx tmp_target; + + /* If we want to use a nontemporal store, force the value to + register first. */ + tmp_target = nontemporal ? NULL_RTX : target; + temp = expand_expr_real (exp, tmp_target, GET_MODE (target), (call_param_p ? EXPAND_STACK_PARM : EXPAND_NORMAL), &alt_rtl); @@ -4591,6 +4637,11 @@ store_expr (tree exp, rtx target, int call_param_p) emit_block_move (target, temp, expr_size (exp), (call_param_p ? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL)); + else if (nontemporal + && emit_storent_insn (target, temp)) + /* If we managed to emit a nontemporal store, there is nothing else to + do. */ + ; else { temp = force_operand (temp, target); @@ -4941,7 +4992,7 @@ store_constructor_field (rtx target, unsigned HOST_WIDE_INT bitsize, store_constructor (exp, target, cleared, bitsize / BITS_PER_UNIT); } else - store_field (target, bitsize, bitpos, mode, exp, type, alias_set); + store_field (target, bitsize, bitpos, mode, exp, type, alias_set, false); } /* Store the value of constructor EXP into the rtx TARGET. @@ -5291,7 +5342,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size) = gen_reg_rtx (promote_mode (domain, DECL_MODE (index), &unsignedp, 0)); SET_DECL_RTL (index, index_r); - store_expr (lo_index, index_r, 0); + store_expr (lo_index, index_r, 0, false); /* Build the head of the loop. */ do_pending_stack_adjust (); @@ -5318,7 +5369,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size) store_constructor (value, xtarget, cleared, bitsize / BITS_PER_UNIT); else - store_expr (value, xtarget, 0); + store_expr (value, xtarget, 0, false); /* Generate a conditional jump to exit the loop. */ exit_cond = build2 (LT_EXPR, integer_type_node, @@ -5329,7 +5380,8 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size) the loop. */ expand_assignment (index, build2 (PLUS_EXPR, TREE_TYPE (index), - index, integer_one_node)); + index, integer_one_node), + false); emit_jump (loop_start); @@ -5360,7 +5412,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size) expand_normal (position), highest_pow2_factor (position)); xtarget = adjust_address (xtarget, mode, 0); - store_expr (value, xtarget, 0); + store_expr (value, xtarget, 0, false); } else { @@ -5522,11 +5574,14 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size) ALIAS_SET is the alias set for the destination. This value will (in general) be different from that for TARGET, since TARGET is a - reference to the containing structure. */ + reference to the containing structure. + + If NONTEMPORAL is true, try generating a nontemporal store. */ static rtx store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos, - enum machine_mode mode, tree exp, tree type, int alias_set) + enum machine_mode mode, tree exp, tree type, int alias_set, + bool nontemporal) { HOST_WIDE_INT width_mask = 0; @@ -5561,7 +5616,8 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos, if (bitsize != (HOST_WIDE_INT) GET_MODE_BITSIZE (GET_MODE (target))) emit_move_insn (object, target); - store_field (blk_object, bitsize, bitpos, mode, exp, type, alias_set); + store_field (blk_object, bitsize, bitpos, mode, exp, type, alias_set, + nontemporal); emit_move_insn (target, object); @@ -5574,7 +5630,7 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos, /* We're storing into a struct containing a single __complex. */ gcc_assert (!bitpos); - return store_expr (exp, target, 0); + return store_expr (exp, target, 0, nontemporal); } /* If the structure is in a register or if the component @@ -5675,7 +5731,7 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos, if (!MEM_KEEP_ALIAS_SET_P (to_rtx) && MEM_ALIAS_SET (to_rtx) != 0) set_mem_alias_set (to_rtx, alias_set); - return store_expr (exp, to_rtx, 0); + return store_expr (exp, to_rtx, 0, nontemporal); } } @@ -7831,7 +7887,8 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, /* Store data into beginning of memory target. */ store_expr (TREE_OPERAND (exp, 0), adjust_address (target, TYPE_MODE (valtype), 0), - modifier == EXPAND_STACK_PARM); + modifier == EXPAND_STACK_PARM, + false); else { @@ -7844,7 +7901,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, * BITS_PER_UNIT), (HOST_WIDE_INT) GET_MODE_BITSIZE (mode)), 0, TYPE_MODE (valtype), TREE_OPERAND (exp, 0), - type, 0); + type, 0, false); } /* Return the entire union. */ @@ -8760,13 +8817,15 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, op1 = gen_label_rtx (); jumpifnot (TREE_OPERAND (exp, 0), op0); store_expr (TREE_OPERAND (exp, 1), temp, - modifier == EXPAND_STACK_PARM); + modifier == EXPAND_STACK_PARM, + false); emit_jump_insn (gen_jump (op1)); emit_barrier (); emit_label (op0); store_expr (TREE_OPERAND (exp, 2), temp, - modifier == EXPAND_STACK_PARM); + modifier == EXPAND_STACK_PARM, + false); emit_label (op1); OK_DEFER_POP; @@ -8781,7 +8840,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, tree lhs = TREE_OPERAND (exp, 0); tree rhs = TREE_OPERAND (exp, 1); gcc_assert (ignore); - expand_assignment (lhs, rhs); + expand_assignment (lhs, rhs, false); return const0_rtx; } @@ -8813,13 +8872,14 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, do_jump (TREE_OPERAND (rhs, 1), value ? label : 0, value ? 0 : label); - expand_assignment (lhs, build_int_cst (TREE_TYPE (rhs), value)); + expand_assignment (lhs, build_int_cst (TREE_TYPE (rhs), value), + MOVE_NONTEMPORAL (exp)); do_pending_stack_adjust (); emit_label (label); return const0_rtx; } - expand_assignment (lhs, rhs); + expand_assignment (lhs, rhs, MOVE_NONTEMPORAL (exp)); return const0_rtx; } |