diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h index efa46ac0b8799b5849b609d591186e26e5cb37ff..cc74a816fcc6458aa065246a30a4d2184692ad74 100644 --- a/gcc/config/aarch64/aarch64.h +++ b/gcc/config/aarch64/aarch64.h @@ -34,7 +34,8 @@ #define REGISTER_TARGET_PRAGMAS() aarch64_register_pragmas () -/* Target machine storage layout. */ +/* Target machine storage layout. See also + TARGET_PROMOTE_FUNCTION_ARGS_SUBREG_P. */ #define PROMOTE_MODE(MODE, UNSIGNEDP, TYPE) \ if (GET_MODE_CLASS (MODE) == MODE_INT \ diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc index 2f559600cff55af9d468e8d0810545583cc986f5..252d6c2af72afc1dfee1a86644a5753784b41f59 100644 --- a/gcc/config/aarch64/aarch64.cc +++ b/gcc/config/aarch64/aarch64.cc @@ -3736,6 +3736,57 @@ aarch64_array_mode_supported_p (machine_mode mode, return false; } +/* Implement target hook TARGET_PROMOTE_FUNCTION_ARGS_SUBREG_P to complement + PROMOTE_MODE. If any argument promotion was done, do them as subregs. */ +static bool +aarch64_promote_function_args_subreg_p (machine_mode mode, + machine_mode promoted_mode, + int /* unsignedp */, tree parm) +{ + bool candidate_p = GET_MODE_CLASS (mode) == MODE_INT + && GET_MODE_CLASS (promoted_mode) == MODE_INT + && known_lt (GET_MODE_SIZE (mode), 4) + && promoted_mode == SImode; + + if (!candidate_p) + return false; + + if (!parm || !is_gimple_reg (parm)) + return true; + + tree var = parm; + if (!VAR_P (var)) + { + if (TREE_CODE (parm) == SSA_NAME + && !(var = SSA_NAME_VAR (var))) + return true; + else if (TREE_CODE (parm) != PARM_DECL) + return true; + } + + /* If the variable is used inside a comparison which sets CC then we should + still promote using an extend. By doing this we make it easier to use + cbz/cbnz but also repeatedly having to test the value in certain + circumstances like nested if values that test the same value with calls + in between. */ + tree ssa_var = ssa_default_def (cfun, var); + if (!ssa_var) + return true; + + const ssa_use_operand_t *const head = &(SSA_NAME_IMM_USE_NODE (ssa_var)); + const ssa_use_operand_t *ptr; + + for (ptr = head->next; ptr != head; ptr = ptr->next) + if (USE_STMT(ptr) && is_gimple_assign (USE_STMT (ptr))) + { + tree_code code = gimple_assign_rhs_code (USE_STMT(ptr)); + if (TREE_CODE_CLASS (code) == tcc_comparison) + return false; + } + + return true; +} + /* MODE is some form of SVE vector mode. For data modes, return the number of vector register bits that each element of MODE occupies, such as 64 for both VNx2DImode and VNx2SImode (where each 32-bit value is stored @@ -27490,6 +27541,10 @@ aarch64_libgcc_floating_mode_supported_p #undef TARGET_ARRAY_MODE_SUPPORTED_P #define TARGET_ARRAY_MODE_SUPPORTED_P aarch64_array_mode_supported_p +#undef TARGET_PROMOTE_FUNCTION_ARGS_SUBREG_P +#define TARGET_PROMOTE_FUNCTION_ARGS_SUBREG_P \ + aarch64_promote_function_args_subreg_p + #undef TARGET_VECTORIZE_CREATE_COSTS #define TARGET_VECTORIZE_CREATE_COSTS aarch64_vectorize_create_costs diff --git a/gcc/testsuite/gcc.target/aarch64/apc-subreg.c b/gcc/testsuite/gcc.target/aarch64/apc-subreg.c new file mode 100644 index 0000000000000000000000000000000000000000..2d7563a11ce11fa677f7ad4bf2a090e6a136e4d9 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/apc-subreg.c @@ -0,0 +1,103 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-O" } */ +/* { dg-final { check-function-bodies "**" "" "" } } */ + +#include + +/* +** f0: +** mvn w0, w0 +** ret +*/ +uint8_t f0 (uint8_t xr){ + return (uint8_t) (0xff - xr); +} + +/* +** f1: +** mvn w0, w0 +** ret +*/ +int8_t f1 (int8_t xr){ + return (int8_t) (0xff - xr); +} + +/* +** f2: +** mvn w0, w0 +** ret +*/ +uint16_t f2 (uint16_t xr){ + return (uint16_t) (0xffFF - xr); +} + +/* +** f3: +** mvn w0, w0 +** ret +*/ +uint32_t f3 (uint32_t xr){ + return (uint32_t) (0xffFFffff - xr); +} + +/* +** f4: +** mvn x0, x0 +** ret +*/ +uint64_t f4 (uint64_t xr){ + return (uint64_t) (0xffFFffffffffffff - xr); +} + +/* +** f5: +** mvn w0, w0 +** sub w0, w0, w1 +** ret +*/ +uint8_t f5 (uint8_t xr, uint8_t xc){ + return (uint8_t) (0xff - xr - xc); +} + +/* +** f6: +** mvn w0, w0 +** and w0, w0, 255 +** and w1, w1, 255 +** mul w0, w0, w1 +** ret +*/ +uint16_t f6 (uint8_t xr, uint8_t xc){ + return ((uint8_t) (0xff - xr)) * xc; +} + +/* +** f7: +** and w0, w0, 255 +** and w1, w1, 255 +** mul w0, w0, w1 +** ret +*/ +uint16_t f7 (uint8_t xr, uint8_t xc){ + return xr * xc; +} + +/* +** f8: +** mul w0, w0, w1 +** and w0, w0, 255 +** ret +*/ +uint16_t f8 (uint8_t xr, uint8_t xc){ + return (uint8_t)(xr * xc); +} + +/* +** f9: +** and w0, w0, 255 +** add w0, w0, w1 +** ret +*/ +uint16_t f9 (uint8_t xr, uint16_t xc){ + return xr + xc; +}