/* A class for building vector tree constants. | |

Copyright (C) 2017-2019 Free Software Foundation, Inc. | |

This file is part of GCC. | |

GCC is free software; you can redistribute it and/or modify it under | |

the terms of the GNU General Public License as published by the Free | |

Software Foundation; either version 3, or (at your option) any later | |

version. | |

GCC is distributed in the hope that it will be useful, but WITHOUT ANY | |

WARRANTY; without even the implied warranty of MERCHANTABILITY or | |

FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |

for more details. | |

You should have received a copy of the GNU General Public License | |

along with GCC; see the file COPYING3. If not see | |

<http://www.gnu.org/licenses/>. */ | |

#include "config.h" | |

#include "system.h" | |

#include "coretypes.h" | |

#include "tree.h" | |

#include "fold-const.h" | |

#include "tree-vector-builder.h" | |

/* Try to start building a new vector of type TYPE that holds the result of | |

a unary operation on VECTOR_CST T. ALLOW_STEPPED_P is true if the | |

operation can handle stepped encodings directly, without having to | |

expand the full sequence. | |

Return true if the operation is possible, which it always is when | |

ALLOW_STEPPED_P is true. Leave the builder unchanged otherwise. */ | |

bool | |

tree_vector_builder::new_unary_operation (tree type, tree t, | |

bool allow_stepped_p) | |

{ | |

poly_uint64 full_nelts = TYPE_VECTOR_SUBPARTS (type); | |

gcc_assert (known_eq (full_nelts, TYPE_VECTOR_SUBPARTS (TREE_TYPE (t)))); | |

unsigned int npatterns = VECTOR_CST_NPATTERNS (t); | |

unsigned int nelts_per_pattern = VECTOR_CST_NELTS_PER_PATTERN (t); | |

if (!allow_stepped_p && nelts_per_pattern > 2) | |

{ | |

if (!full_nelts.is_constant ()) | |

return false; | |

npatterns = full_nelts.to_constant (); | |

nelts_per_pattern = 1; | |

} | |

new_vector (type, npatterns, nelts_per_pattern); | |

return true; | |

} | |

/* Try to start building a new vector of type TYPE that holds the result of | |

a binary operation on VECTOR_CSTs T1 and T2. ALLOW_STEPPED_P is true if | |

the operation can handle stepped encodings directly, without having to | |

expand the full sequence. | |

Return true if the operation is possible. Leave the builder unchanged | |

otherwise. */ | |

bool | |

tree_vector_builder::new_binary_operation (tree type, tree t1, tree t2, | |

bool allow_stepped_p) | |

{ | |

poly_uint64 full_nelts = TYPE_VECTOR_SUBPARTS (type); | |

gcc_assert (known_eq (full_nelts, TYPE_VECTOR_SUBPARTS (TREE_TYPE (t1))) | |

&& known_eq (full_nelts, TYPE_VECTOR_SUBPARTS (TREE_TYPE (t2)))); | |

/* Conceptually we split the patterns in T1 and T2 until we have | |

an equal number for both. Each split pattern requires the same | |

number of elements per pattern as the original. E.g. splitting: | |

{ 1, 2, 3, ... } | |

into two gives: | |

{ 1, 3, 5, ... } | |

{ 2, 4, 6, ... } | |

while splitting: | |

{ 1, 0, ... } | |

into two gives: | |

{ 1, 0, ... } | |

{ 0, 0, ... }. */ | |

unsigned int npatterns = least_common_multiple (VECTOR_CST_NPATTERNS (t1), | |

VECTOR_CST_NPATTERNS (t2)); | |

unsigned int nelts_per_pattern = MAX (VECTOR_CST_NELTS_PER_PATTERN (t1), | |

VECTOR_CST_NELTS_PER_PATTERN (t2)); | |

if (!allow_stepped_p && nelts_per_pattern > 2) | |

{ | |

if (!full_nelts.is_constant ()) | |

return false; | |

npatterns = full_nelts.to_constant (); | |

nelts_per_pattern = 1; | |

} | |

new_vector (type, npatterns, nelts_per_pattern); | |

return true; | |

} | |

/* Return the number of elements that the caller needs to operate on in | |

order to handle a binary operation on VECTOR_CSTs T1 and T2. This static | |

function is used instead of new_binary_operation if the result of the | |

operation is not a VECTOR_CST. */ | |

unsigned int | |

tree_vector_builder::binary_encoded_nelts (tree t1, tree t2) | |

{ | |

poly_uint64 nelts = TYPE_VECTOR_SUBPARTS (TREE_TYPE (t1)); | |

gcc_assert (known_eq (nelts, TYPE_VECTOR_SUBPARTS (TREE_TYPE (t2)))); | |

/* See new_binary_operation for details. */ | |

unsigned int npatterns = least_common_multiple (VECTOR_CST_NPATTERNS (t1), | |

VECTOR_CST_NPATTERNS (t2)); | |

unsigned int nelts_per_pattern = MAX (VECTOR_CST_NELTS_PER_PATTERN (t1), | |

VECTOR_CST_NELTS_PER_PATTERN (t2)); | |

unsigned HOST_WIDE_INT const_nelts; | |

if (nelts.is_constant (&const_nelts)) | |

return MIN (npatterns * nelts_per_pattern, const_nelts); | |

return npatterns * nelts_per_pattern; | |

} | |

/* Return a vector element with the value BASE + FACTOR * STEP. */ | |

tree | |

tree_vector_builder::apply_step (tree base, unsigned int factor, | |

const wide_int &step) const | |

{ | |

return wide_int_to_tree (TREE_TYPE (base), | |

wi::to_wide (base) + factor * step); | |

} | |

/* Return a VECTOR_CST for the current constant. */ | |

tree | |

tree_vector_builder::build () | |

{ | |

finalize (); | |

gcc_assert (pow2p_hwi (npatterns ())); | |

tree v = make_vector (exact_log2 (npatterns ()), nelts_per_pattern ()); | |

TREE_TYPE (v) = m_type; | |

memcpy (VECTOR_CST_ENCODED_ELTS (v), address (), | |

encoded_nelts () * sizeof (tree)); | |

return v; | |

} |