On 11/9/24 12:43 PM, Mariam Arutunian wrote:
Add two new internal functions (IFN_CRC, IFN_CRC_REV), to provide faster
CRC generation.
One performs bit-forward and the other bit-reversed CRC computation.
If CRC optabs are supported, they are used for the CRC computation.
Otherwise, table-based CRC is generated.
The supported data and CRC sizes are 8, 16, 32, and 64 bits.
The polynomial is without the leading 1.
A table with 256 elements is used to store precomputed CRCs.
For the reflection of inputs and the output, a simple algorithm involving
SHIFT, AND, and OR operations is used.
gcc/
* doc/md.texi (crc@var{m}@var{n}4,
crc_rev@var{m}@var{n}4): Document.
* expr.cc (calculate_crc): New function.
(assemble_crc_table): Likewise.
(generate_crc_table): Likewise.
(calculate_table_based_CRC): Likewise.
(emit_crc): Likewise.
(expand_crc_table_based): Likewise.
(gen_common_operation_to_reflect): Likewise.
(reflect_64_bit_value): Likewise.
(reflect_32_bit_value): Likewise.
(reflect_16_bit_value): Likewise.
(reflect_8_bit_value): Likewise.
(generate_reflecting_code_standard): Likewise.
(expand_reversed_crc_table_based): Likewise.
* expr.h (generate_reflecting_code_standard): New function declaration.
(expand_crc_table_based): Likewise.
(expand_reversed_crc_table_based): Likewise.
* internal-fn.cc: (crc_direct): Define.
(direct_crc_optab_supported_p): Likewise.
(expand_crc_optab_fn): New function
* internal-fn.def (CRC, CRC_REV): New internal functions.
* optabs.def (crc_optab, crc_rev_optab): New optabs.
Signed-off-by: Mariam Arutunian <mariamarutun...@gmail.com
<mailto:mariamarutun...@gmail.com>>
Co-authored-by: Joern Rennecke <joern.renne...@embecosm.com
<mailto:joern.renne...@embecosm.com>>
Mentored-by: Jeff Law <j...@ventanamicro.com <mailto:j...@ventanamicro.com>>
0001-Implement-internal-functions-for-efficient-CRC-compu.patch
---
gcc/doc/md.texi | 14 ++
gcc/expr.cc | 372 ++++++++++++++++++++++++++++++++++++++++++++
gcc/expr.h | 6 +
gcc/internal-fn.cc | 54 +++++++
gcc/internal-fn.def | 2 +
gcc/optabs.def | 2 +
6 files changed, 450 insertions(+)
diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi
index a9259112251..913d1f96373 100644
--- a/gcc/doc/md.texi
+++ b/gcc/doc/md.texi
@@ -8591,6 +8591,20 @@ Return 1 if operand 1 is a normal floating point number
and 0
otherwise. @var{m} is a scalar floating point mode. Operand 0
has mode @code{SImode}, and operand 1 has mode @var{m}.
+@cindex @code{crc@var{m}@var{n}4} instruction pattern
+@item @samp{crc@var{m}@var{n}4}
+Calculate a bit-forward CRC using operands 1, 2 and 3,
+then store the result in operand 0.
+Operands 1 is the initial CRC, operands 2 is the data and operands 3 is the
+polynomial without leading 1.
+Operands 0, 1 and 3 have mode @var{n} and operand 2 has mode @var{m}, where
+both modes are integers. The size of CRC to be calculated is determined by the
+mode; for example, if @var{n} is 'hi', a CRC16 is calculated.
Nit. When we reference modes in documentation we typically do so with
something like this @code{HImode}.
+
+/* Converts and moves a CRC value to a target register.
+
+ CRC_MODE is the mode (data type) of the CRC value.
+ CRC is the initial CRC value.
+ OP0 is the target register. */
+
+void
+emit_crc (machine_mode crc_mode, rtx* crc, rtx* op0)
+{
+ if (word_mode != crc_mode)
+ {
+ rtx tgt = simplify_gen_subreg (word_mode, *op0, crc_mode, 0);
Can CRC_MODE ever be wider than WORD_MODE?
If so, then that last argument needs adjustment to cope with endianness.
On the optimistic assumption that we're always generating a
paradoxical, I'm putting a gcc_assert in my local copy for testing purposes.
+ rtx crc_low = gen_lowpart (crc_mode, *crc);
+ if (SUBREG_P (*op0) && SUBREG_PROMOTED_VAR_P (*op0))
+ convert_move (tgt, crc_low, SUBREG_PROMOTED_SIGN (*op0));
+ else
+ convert_move (tgt, crc_low, 0);
+ }
+ else
+ emit_move_insn (*op0, *crc);
Formatting nit. The final "else" and "emit_move_insn" call are
mis-indented. I've fix that in my local copy.
+
+/* Reflect 64-bit value for the 64-bit target. */
+
+void
+reflect_64_bit_value (rtx *op)
+{
+ gen_common_operation_to_reflect (op, 0x00000000FFFFFFFF,
+ 0xFFFFFFFF00000000, 32);
+ gen_common_operation_to_reflect (op, 0x0000FFFF0000FFFF,
+ 0xFFFF0000FFFF0000, 16);
+ gen_common_operation_to_reflect (op, 0x00FF00FF00FF00FF,
+ 0xFF00FF00FF00FF00, 8);
+ gen_common_operation_to_reflect (op, 0x0F0F0F0F0F0F0F0F,
+ 0xF0F0F0F0F0F0F0F0, 4);
+ gen_common_operation_to_reflect (op, 0x3333333333333333,
+ 0xCCCCCCCCCCCCCCCC, 2);
+ gen_common_operation_to_reflect (op, 0x5555555555555555,
+ 0xAAAAAAAAAAAAAAAA, 1);
+}
I should have caught this before. These constants probably need to be
wrapped by a HOST_WIDE_INT_C. I'll fix that locally too. I don't think
the other routines for 32, 16 or 8 bit need this.
jeff