diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h index 0ca4d84dbfae..2cd5667d4fbb 100644 --- a/gcc/config/aarch64/aarch64-protos.h +++ b/gcc/config/aarch64/aarch64-protos.h @@ -510,6 +510,7 @@ void aarch64_post_cfi_startproc (void); poly_int64 aarch64_initial_elimination_offset (unsigned, unsigned); int aarch64_get_condition_code (rtx); bool aarch64_address_valid_for_prefetch_p (rtx, bool); +bool aarch64_address_valid_for_unscaled_prefetch_p (rtx, bool); bool aarch64_bitmask_imm (HOST_WIDE_INT val, machine_mode); unsigned HOST_WIDE_INT aarch64_and_split_imm1 (HOST_WIDE_INT val_in); unsigned HOST_WIDE_INT aarch64_and_split_imm2 (HOST_WIDE_INT val_in); diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c index 63b83158f9f5..510b6de98c8d 100644 --- a/gcc/config/aarch64/aarch64.c +++ b/gcc/config/aarch64/aarch64.c @@ -9675,6 +9675,29 @@ aarch64_address_valid_for_prefetch_p (rtx x, bool strict_p) return addr.type != ADDRESS_REG_WB; } +/* Return true if the address X is valid for a PRFUM instruction. + STRICT_P is true if we should do strict checking with + aarch64_classify_address. */ + +bool +aarch64_address_valid_for_unscaled_prefetch_p (rtx x, bool strict_p) +{ + struct aarch64_address_info addr; + + /* PRFUM accepts the same addresses as DImode, but constrained to a range + -256..255. */ + bool res = aarch64_classify_address (&addr, x, DImode, strict_p); + if (!res) + return false; + + if (addr.offset && ((INTVAL (addr.offset) > 255) + || (INTVAL (addr.offset) < -256))) + return false; + + /* ... except writeback forms. */ + return addr.type != ADDRESS_REG_WB; +} + bool aarch64_symbolic_address_p (rtx x) { diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md index d9c5803e9989..a428bce4ae40 100644 --- a/gcc/config/aarch64/aarch64.md +++ b/gcc/config/aarch64/aarch64.md @@ -840,6 +840,37 @@ [(set_attr "type" "load_4")] ) +(define_insn "prefetch_unscaled" + [(prefetch (match_operand:DI 0 "aarch64_unscaled_prefetch_operand" "Du") + (match_operand:QI 1 "const_int_operand" "") + (match_operand:QI 2 "const_int_operand" ""))] + "" + { + const char * pftype[2][4] = + { + {"prfum\\tPLDL1STRM, %0", + "prfum\\tPLDL3KEEP, %0", + "prfum\\tPLDL2KEEP, %0", + "prfum\\tPLDL1KEEP, %0"}, + {"prfum\\tPSTL1STRM, %0", + "prfum\\tPSTL3KEEP, %0", + "prfum\\tPSTL2KEEP, %0", + "prfum\\tPSTL1KEEP, %0"}, + }; + + int locality = INTVAL (operands[2]); + + gcc_assert (IN_RANGE (locality, 0, 3)); + + /* PRFUM accepts the same addresses as a 64-bit LDR so wrap + the address into a DImode MEM so that aarch64_print_operand knows + how to print it. */ + operands[0] = gen_rtx_MEM (DImode, operands[0]); + return pftype[INTVAL(operands[1])][locality]; + } + [(set_attr "type" "load_4")] +) + (define_insn "trap" [(trap_if (const_int 1) (const_int 8))] "" diff --git a/gcc/config/aarch64/constraints.md b/gcc/config/aarch64/constraints.md index 09c2b7283e34..e5813703a2b7 100644 --- a/gcc/config/aarch64/constraints.md +++ b/gcc/config/aarch64/constraints.md @@ -472,6 +472,11 @@ An address valid for a prefetch instruction." (match_test "aarch64_address_valid_for_prefetch_p (op, true)")) +(define_address_constraint "Du" + "@internal + An address valid for a prefetch instruction with an unscaled offset." + (match_test "aarch64_address_valid_for_unscaled_prefetch_p (op, true)")) + (define_constraint "vgb" "@internal A constraint that matches an immediate offset valid for SVE LD1B diff --git a/gcc/config/aarch64/predicates.md b/gcc/config/aarch64/predicates.md index 75612fd9f66c..d0f748864bec 100644 --- a/gcc/config/aarch64/predicates.md +++ b/gcc/config/aarch64/predicates.md @@ -257,6 +257,9 @@ (define_predicate "aarch64_prefetch_operand" (match_test "aarch64_address_valid_for_prefetch_p (op, false)")) +(define_predicate "aarch64_unscaled_prefetch_operand" + (match_test "aarch64_address_valid_for_unscaled_prefetch_p (op, false)")) + (define_predicate "aarch64_valid_symref" (match_code "const, symbol_ref, label_ref") {