This implements constant pool entry sharing for CONST_VECTORs with the same bit-pattern by canonicalizing them to the same-sized mode with the least number of elements. Ideally we would be able to hash and compare the in-memory representation of a constant (together with its alignment requirement), but I'm not aware of any RTL facility that would be equivalent to native_{interpret,encode}_expr. So this just handles CONST_VECTORs as requested in the bugreport.
Bootstrap and regtest pending on x86_64-unknown-linux-gnu. Any comments? It would be interesting to pursue a way to share constant parts (beware of endian and odd alignment issues) by means of simply inserting more entries into the hashtable. Not sure if offsetted .LC references are valid as result of force_const_mem though (well, we could try to share the part at offset zero). Thanks, Richard. 2012-08-14 Richard Guenther <rguent...@suse.de> PR middle-end/54201 * varasm.c (force_const_mem): Canonicalize CONST_VECTORs to the same-sized mode with the least number of elements for the purpose of constant slot sharing. * gcc.target/i386/pr54201.c: New testcase. Index: gcc/varasm.c =================================================================== *** gcc/varasm.c (revision 190381) --- gcc/varasm.c (working copy) *************** force_const_mem (enum machine_mode mode, *** 3482,3489 **** { struct constant_descriptor_rtx *desc, tmp; struct rtx_constant_pool *pool; char label[256]; ! rtx def, symbol; hashval_t hash; unsigned int align; void **slot; --- 3482,3490 ---- { struct constant_descriptor_rtx *desc, tmp; struct rtx_constant_pool *pool; + enum machine_mode orig_mode = mode; char label[256]; ! rtx def, symbol, res; hashval_t hash; unsigned int align; void **slot; *************** force_const_mem (enum machine_mode mode, *** 3500,3505 **** --- 3501,3518 ---- ? shared_constant_pool : crtl->varasm.pool); + /* Canonicalize CONST_VECTORs to the mode with the least number of + elements assuming that alignment requirements are not worse + for the original mode. */ + if (GET_CODE (x) == CONST_VECTOR) + { + while (GET_MODE_SIZE (mode) + == GET_MODE_SIZE (GET_MODE_WIDER_MODE (mode))) + mode = GET_MODE_WIDER_MODE (mode); + x = simplify_subreg (mode, x, orig_mode, 0); + gcc_assert (x != NULL_RTX); + } + /* Lookup the value in the hashtable. */ tmp.constant = x; tmp.mode = mode; *************** force_const_mem (enum machine_mode mode, *** 3509,3515 **** /* If the constant was already present, return its memory. */ if (desc) ! return copy_rtx (desc->mem); /* Otherwise, create a new descriptor. */ desc = ggc_alloc_constant_descriptor_rtx (); --- 3522,3532 ---- /* If the constant was already present, return its memory. */ if (desc) ! { ! res = copy_rtx (desc->mem); ! PUT_MODE (res, orig_mode); ! return res; ! } /* Otherwise, create a new descriptor. */ desc = ggc_alloc_constant_descriptor_rtx (); *************** force_const_mem (enum machine_mode mode, *** 3573,3579 **** if (GET_CODE (x) == LABEL_REF) LABEL_PRESERVE_P (XEXP (x, 0)) = 1; ! return copy_rtx (def); } /* Given a constant pool SYMBOL_REF, return the corresponding constant. */ --- 3590,3598 ---- if (GET_CODE (x) == LABEL_REF) LABEL_PRESERVE_P (XEXP (x, 0)) = 1; ! res = copy_rtx (def); ! PUT_MODE (res, orig_mode); ! return res; } /* Given a constant pool SYMBOL_REF, return the corresponding constant. */ Index: gcc/testsuite/gcc.target/i386/pr54201.c =================================================================== *** gcc/testsuite/gcc.target/i386/pr54201.c (revision 0) --- gcc/testsuite/gcc.target/i386/pr54201.c (working copy) *************** *** 0 **** --- 1,15 ---- + /* { dg-do compile } */ + /* { dg-options "-O -msse2" } */ + + #include <emmintrin.h> + + __m128i test(__m128i value) + { + __m128i mask = _mm_set1_epi8(1); + return _mm_cmpeq_epi8(_mm_and_si128(value, mask), mask); + } + + /* We should share constant slots for V16QI { 1, ... 1 } and its V2DI + representation. */ + + /* { dg-final { scan-assembler-not "LC1" } } */