This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Faster streaming of enums


On Wed, May 25, 2011 at 11:45 AM, Jan Hubicka <hubicka@ucw.cz> wrote:
> Hi,
> after fixing 1 byte i/o function call and most of hash table overhead,
> functions to handle ulebs and slebs shows top in profile. ?We use them in
> many cases where we know value range of the operand will fit in 1 byte. In
> particular to handle enums.
> This is also dangerous since we generally assume enums to be in their value
> range.
>
> This patch adds i/o bits for enums and integers in range that should inline
> well and add some sanity checking.
>
> I converted only tree streamer tags, but if accepted, I will convert more.
>
> Bootstrapped/regtested x86_64-linux, OK?
>
> ? ? ? ?* lto-streamer-out.c (output_record_start): Use lto_output_enum
> ? ? ? ?(lto_output_tree): Use output_record_start.
> ? ? ? ?* lto-streamer-in.c (input_record_start): Use lto_input_enum
> ? ? ? ?(lto_get_pickled_tree): Use input_record_start.
> ? ? ? ?* lto-section-in.c (lto_section_overrun): Turn into fatal error.
> ? ? ? ?(lto_value_range_error): New function.
> ? ? ? ?* lto-streamer.h (lto_value_range_error): Declare.
> ? ? ? ?(lto_output_int_in_range, lto_input_int_in_range): New functions.
> ? ? ? ?(lto_output_enum, lto_input_enum): New macros.
> Index: lto-streamer-out.c
> ===================================================================
> *** lto-streamer-out.c ?(revision 174175)
> --- lto-streamer-out.c ?(working copy)
> *************** output_sleb128 (struct output_block *ob,
> *** 270,281 ****
>
> ?/* Output the start of a record with TAG to output block OB. ?*/
>
> ! static void
> ?output_record_start (struct output_block *ob, enum LTO_tags tag)
> ?{
> ! ? /* Make sure TAG fits inside an unsigned int. ?*/
> ! ? gcc_assert (tag == (enum LTO_tags) (unsigned) tag);
> ! ? output_uleb128 (ob, tag);
> ?}
>
>
> --- 270,279 ----
>
> ?/* Output the start of a record with TAG to output block OB. ?*/
>
> ! static inline void
> ?output_record_start (struct output_block *ob, enum LTO_tags tag)
> ?{
> ! ? lto_output_enum (ob->main_stream, LTO_tags, LTO_NUM_TAGS, tag);
> ?}
>
>
> *************** lto_output_tree (struct output_block *ob
> *** 1401,1407 ****
> ? ? ? ? will instantiate two different nodes for the same object. ?*/
> ? ? ? ?output_record_start (ob, LTO_tree_pickle_reference);
> ? ? ? ?output_uleb128 (ob, ix);
> ! ? ? ? output_uleb128 (ob, lto_tree_code_to_tag (TREE_CODE (expr)));
> ? ? ?}
> ? ?else if (lto_stream_as_builtin_p (expr))
> ? ? ?{
> --- 1399,1405 ----
> ? ? ? ? will instantiate two different nodes for the same object. ?*/
> ? ? ? ?output_record_start (ob, LTO_tree_pickle_reference);
> ? ? ? ?output_uleb128 (ob, ix);
> ! ? ? ? output_record_start (ob, lto_tree_code_to_tag (TREE_CODE (expr)));

I'd prefer lto_output_enum here as we don't really start a new output
record but just emit something for a sanity check.

> ? ? ?}
> ? ?else if (lto_stream_as_builtin_p (expr))
> ? ? ?{
> Index: lto-streamer-in.c
> ===================================================================
> *** lto-streamer-in.c ? (revision 174175)
> --- lto-streamer-in.c ? (working copy)
> *************** lto_input_string (struct data_in *data_i
> *** 231,241 ****
>
> ?/* Return the next tag in the input block IB. ?*/
>
> ! static enum LTO_tags
> ?input_record_start (struct lto_input_block *ib)
> ?{
> ! ? enum LTO_tags tag = (enum LTO_tags) lto_input_uleb128 (ib);
> ! ? return tag;
> ?}
>
>
> --- 231,240 ----
>
> ?/* Return the next tag in the input block IB. ?*/
>
> ! static inline enum LTO_tags
> ?input_record_start (struct lto_input_block *ib)
> ?{
> ! ? return lto_input_enum (ib, LTO_tags, LTO_NUM_TAGS);
> ?}
>
>
> *************** lto_get_pickled_tree (struct lto_input_b
> *** 2558,2564 ****
> ? ?enum LTO_tags expected_tag;
>
> ? ?ix = lto_input_uleb128 (ib);
> ! ? expected_tag = (enum LTO_tags) lto_input_uleb128 (ib);
>
> ? ?result = lto_streamer_cache_get (data_in->reader_cache, ix);
> ? ?gcc_assert (result
> --- 2557,2563 ----
> ? ?enum LTO_tags expected_tag;
>
> ? ?ix = lto_input_uleb128 (ib);
> ! ? expected_tag = input_record_start (ib);

Likewise use input_enum.

> ? ?result = lto_streamer_cache_get (data_in->reader_cache, ix);
> ? ?gcc_assert (result
> Index: lto-section-in.c
> ===================================================================
> *** lto-section-in.c ? ?(revision 174175)
> --- lto-section-in.c ? ?(working copy)
> *************** lto_get_function_in_decl_state (struct l
> *** 483,488 ****
> ?void
> ?lto_section_overrun (struct lto_input_block *ib)
> ?{
> ! ? internal_error ("bytecode stream: trying to read %d bytes "
> ! ? ? ? ? ? ? ? ? "after the end of the input buffer", ib->p - ib->len);
> ?}
> --- 483,498 ----
> ?void
> ?lto_section_overrun (struct lto_input_block *ib)
> ?{
> ! ? fatal_error ("bytecode stream: trying to read %d bytes "
> ! ? ? ? ? ? ? ?"after the end of the input buffer", ib->p - ib->len);
> ! }
> !
> ! /* Report out of range value. ?*/
> !
> ! void
> ! lto_value_range_error (const char *purpose, HOST_WIDE_INT val,
> ! ? ? ? ? ? ? ? ? ? ? ?HOST_WIDE_INT min, HOST_WIDE_INT max)
> ! {
> ! ? fatal_error ("%s out of range: Range is %i to %i, value is %i",
> ! ? ? ? ? ? ? ?purpose, (int)min, (int)max, (int)val);
> ?}
> Index: lto-streamer.h
> ===================================================================
> *** lto-streamer.h ? ? ?(revision 174175)
> --- lto-streamer.h ? ? ?(working copy)
> *************** extern int lto_eq_in_decl_state (const v
> *** 771,776 ****
> --- 771,779 ----
> ?extern struct lto_in_decl_state *lto_get_function_in_decl_state (
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?struct lto_file_decl_data *, tree);
> ?extern void lto_section_overrun (struct lto_input_block *) ATTRIBUTE_NORETURN;
> + extern void lto_value_range_error (const char *,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?HOST_WIDE_INT, HOST_WIDE_INT,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?HOST_WIDE_INT) ATTRIBUTE_NORETURN;
>
> ?/* In lto-section-out.c ?*/
> ?extern hashval_t lto_hash_decl_slot_node (const void *);
> *************** lto_input_1_unsigned (struct lto_input_b
> *** 1199,1202 ****
> --- 1202,1267 ----
> ? ?return (ib->data[ib->p++]);
> ?}
>
> + /* Output VAL into OBS and verify it is in range MIN...MAX that is supposed
> + ? ?to be compile time constant.
> + ? ?Be host independent, limit range to 31bits. ?*/
> +
> + static inline void
> + lto_output_int_in_range (struct lto_output_stream *obs,
> + ? ? ? ? ? ? ? ? ? ? ? ?HOST_WIDE_INT min,
> + ? ? ? ? ? ? ? ? ? ? ? ?HOST_WIDE_INT max,
> + ? ? ? ? ? ? ? ? ? ? ? ?HOST_WIDE_INT val)
> + {
> + ? HOST_WIDE_INT range = max - min;
> +
> + ? gcc_checking_assert (val >= min && val <= max && range > 0
> + ? ? ? ? ? ? ? ? ? ? ?&& range < 0x7fffffff);
> +
> + ? val -= min;
> + ? lto_output_1_stream (obs, val & 255);
> + ? if (range >= 0xff)
> + ? ? lto_output_1_stream (obs, (val << 8) & 255);
> + ? if (range >= 0xffff)
> + ? ? lto_output_1_stream (obs, (val << 16) & 255);
> + ? if (range >= 0xffffff)
> + ? ? lto_output_1_stream (obs, (val << 24) & 255);

so you didn't want to create a bitpack_pack_int_in_range and use
bitpacks for enums?  I suppose for some of the remaining cases
packing them into existing bitpacks would be preferable?

> + }
> +
> + /* Input VAL into OBS and verify it is in range MIN...MAX that is supposed
> + ? ?to be compile time constant. ?PURPOSE is used for error reporting. ?*/
> +
> + static inline HOST_WIDE_INT
> + lto_input_int_in_range (struct lto_input_block *ib,
> + ? ? ? ? ? ? ? ? ? ? ? const char *purpose,
> + ? ? ? ? ? ? ? ? ? ? ? HOST_WIDE_INT min,
> + ? ? ? ? ? ? ? ? ? ? ? HOST_WIDE_INT max)
> + {
> + ? HOST_WIDE_INT range = max - min;
> + ? HOST_WIDE_INT val = lto_input_1_unsigned (ib);
> +
> + ? gcc_checking_assert (range > 0);

The assert doesn't match the one during output.

> +
> + ? if (range >= 0xff)
> + ? ? val |= ((HOST_WIDE_INT)lto_input_1_unsigned (ib)) << 8;
> + ? if (range >= 0xffff)
> + ? ? val |= ((HOST_WIDE_INT)lto_input_1_unsigned (ib)) << 16;
> + ? if (range >= 0xffffff)
> + ? ? val |= ((HOST_WIDE_INT)lto_input_1_unsigned (ib)) << 24;
> + ? val += min;
> + ? if (val < min || val > max)
> + ? ? lto_value_range_error (purpose, val, min, max);
> + ? return val;
> + }
> +
> + /* Output VAL of type "enum enum_name" into OBS.
> + ? ?Assume range 0...ENUM_LAST - 1. ?*/
> + #define lto_output_enum(obs,enum_name,enum_last,val) \
> + ? lto_output_int_in_range ((obs), 0, (int)(enum_last) - 1, (int)(val))
> +
> + /* Input enum of type "enum enum_name" from IB.
> + ? ?Assume range 0...ENUM_LAST - 1. ?*/
> + #define lto_input_enum(ib,enum_name,enum_last) \
> + ? (enum enum_name)lto_input_int_in_range ((ib), #enum_name, 0, \
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (int)(enum_last) - 1)
> +
> ?#endif /* GCC_LTO_STREAMER_H ?*/
>


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]