提交 d74dd56a 编写于 作者: J Jesse Zhang

Prevent int128 from requiring more than MAXALIGN alignment.

We backported 128-bit integer support to speed up aggregates (commits
8122e143 and 959277a4) from upstream 9.6 into Greenplum (in
commits 9b164486 and 325e6fcd). However, we forgot to also port a
follow-up fix postgres/postgres@7518049980b, mostly because it's nuanced
and hard to reproduce.

There are two ways to tell the brokenness:

1. On a lucky day, tests would fail on my workstation, but not my laptop (or
   vice versa).

1. If you stare at the generated code for `int8_avg_combine` (and friends),
   you'll notice the compiler uses "aligned" instructions like `movaps` and
   `movdqa` (on AMD64).

Today's my lucky day.

Original commit message from postgres/postgres@7518049980b (by Tom Lane):

> Our initial work with int128 neglected alignment considerations, an
> oversight that came back to bite us in bug #14897 from Vincent Lachenal.
> It is unsurprising that int128 might have a 16-byte alignment requirement;
> what's slightly more surprising is that even notoriously lax Intel chips
> sometimes enforce that.

> Raising MAXALIGN seems out of the question: the costs in wasted disk and
> memory space would be significant, and there would also be an on-disk
> compatibility break.  Nor does it seem very practical to try to allow some
> data structures to have more-than-MAXALIGN alignment requirement, as we'd
> have to push knowledge of that throughout various code that copies data
> structures around.

> The only way out of the box is to make type int128 conform to the system's
> alignment assumptions.  Fortunately, gcc supports that via its
> __attribute__(aligned()) pragma; and since we don't currently support
> int128 on non-gcc-workalike compilers, we shouldn't be losing any platform
> support this way.

> Although we could have just done pg_attribute_aligned(MAXIMUM_ALIGNOF) and
> called it a day, I did a little bit of extra work to make the code more
> portable than that: it will also support int128 on compilers without
> __attribute__(aligned()), if the native alignment of their 128-bit-int
> type is no more than that of int64.

> Add a regression test case that exercises the one known instance of the
> problem, in parallel aggregation over a bigint column.

> This will need to be back-patched, along with the preparatory commit
> 91aec93e.  But let's see what the buildfarm makes of it first.

> Discussion: https://postgr.es/m/20171110185747.31519.28038@wrigleys.postgresql.org

(cherry picked from commit 75180499)
上级 60a08bc2
......@@ -128,9 +128,11 @@ undefine([Ac_cachevar])dnl
# PGAC_TYPE_128BIT_INT
# ---------------------
# Check if __int128 is a working 128 bit integer type, and if so
# define PG_INT128_TYPE to that typename. This currently only detects
# a GCC/clang extension, but support for different environments may be
# added in the future.
# define PG_INT128_TYPE to that typename, and define ALIGNOF_PG_INT128_TYPE
# as its alignment requirement.
#
# This currently only detects a GCC/clang extension, but support for other
# environments may be added in the future.
#
# For the moment we only test for support for 128bit math; support for
# 128bit literals and snprintf is not required.
......@@ -160,6 +162,7 @@ return 1;
[pgac_cv__128bit_int=no])])
if test x"$pgac_cv__128bit_int" = xyes ; then
AC_DEFINE(PG_INT128_TYPE, __int128, [Define to the name of a signed 128-bit integer type.])
AC_CHECK_ALIGNOF(PG_INT128_TYPE)
fi])# PGAC_TYPE_128BIT_INT
......
......@@ -18271,7 +18271,10 @@ _ACEOF
# Compute maximum alignment of any basic type.
# We assume long's alignment is at least as strong as char, short, or int;
# but we must check long long (if it exists) and double.
# but we must check long long (if it is being used for int64) and double.
# Note that we intentionally do not consider any types wider than 64 bits,
# as allowing MAXIMUM_ALIGNOF to exceed 8 would be too much of a penalty
# for disk and memory space.
MAX_ALIGNOF=$ac_cv_alignof_long
if test $MAX_ALIGNOF -lt $ac_cv_alignof_double ; then
......@@ -18345,7 +18348,7 @@ _ACEOF
fi
# Check for extensions offering the integer scalar type __int128.
# Some compilers offer a 128-bit integer scalar type.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for __int128" >&5
$as_echo_n "checking for __int128... " >&6; }
if ${pgac_cv__128bit_int+:} false; then :
......@@ -18395,6 +18398,41 @@ if test x"$pgac_cv__128bit_int" = xyes ; then
$as_echo "#define PG_INT128_TYPE __int128" >>confdefs.h
# The cast to long int works around a bug in the HP C Compiler,
# see AC_CHECK_SIZEOF for more information.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking alignment of PG_INT128_TYPE" >&5
$as_echo_n "checking alignment of PG_INT128_TYPE... " >&6; }
if ${ac_cv_alignof_PG_INT128_TYPE+:} false; then :
$as_echo_n "(cached) " >&6
else
if ac_fn_c_compute_int "$LINENO" "(long int) offsetof (ac__type_alignof_, y)" "ac_cv_alignof_PG_INT128_TYPE" "$ac_includes_default
#ifndef offsetof
# define offsetof(type, member) ((char *) &((type *) 0)->member - (char *) 0)
#endif
typedef struct { char x; PG_INT128_TYPE y; } ac__type_alignof_;"; then :
else
if test "$ac_cv_type_PG_INT128_TYPE" = yes; then
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error 77 "cannot compute alignment of PG_INT128_TYPE
See \`config.log' for more details" "$LINENO" 5; }
else
ac_cv_alignof_PG_INT128_TYPE=0
fi
fi
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_alignof_PG_INT128_TYPE" >&5
$as_echo "$ac_cv_alignof_PG_INT128_TYPE" >&6; }
cat >>confdefs.h <<_ACEOF
#define ALIGNOF_PG_INT128_TYPE $ac_cv_alignof_PG_INT128_TYPE
_ACEOF
fi
# Check for various atomic operations now that we have checked how to declare
......
......@@ -2323,7 +2323,10 @@ AC_CHECK_ALIGNOF(double)
# Compute maximum alignment of any basic type.
# We assume long's alignment is at least as strong as char, short, or int;
# but we must check long long (if it exists) and double.
# but we must check long long (if it is being used for int64) and double.
# Note that we intentionally do not consider any types wider than 64 bits,
# as allowing MAXIMUM_ALIGNOF to exceed 8 would be too much of a penalty
# for disk and memory space.
MAX_ALIGNOF=$ac_cv_alignof_long
if test $MAX_ALIGNOF -lt $ac_cv_alignof_double ; then
......@@ -2344,7 +2347,7 @@ AC_CHECK_TYPES([int8, uint8, int64, uint64], [], [],
# C, but is missing on some old platforms.
AC_CHECK_TYPES(sig_atomic_t, [], [], [#include <signal.h>])
# Check for extensions offering the integer scalar type __int128.
# Some compilers offer a 128-bit integer scalar type.
PGAC_TYPE_128BIT_INT
# Check for various atomic operations now that we have checked how to declare
......
......@@ -414,13 +414,29 @@ typedef unsigned long long int uint64;
/*
* 128-bit signed and unsigned integers
* There currently is only a limited support for the type. E.g. 128bit
* literals and snprintf are not supported; but math is.
* There currently is only limited support for such types.
* E.g. 128bit literals and snprintf are not supported; but math is.
* Also, because we exclude such types when choosing MAXIMUM_ALIGNOF,
* it must be possible to coerce the compiler to allocate them on no
* more than MAXALIGN boundaries.
*/
#if defined(PG_INT128_TYPE)
#define HAVE_INT128
typedef PG_INT128_TYPE int128;
typedef unsigned PG_INT128_TYPE uint128;
#if defined(pg_attribute_aligned) || ALIGNOF_PG_INT128_TYPE <= MAXIMUM_ALIGNOF
#define HAVE_INT128 1
typedef PG_INT128_TYPE int128
#if defined(pg_attribute_aligned)
pg_attribute_aligned(MAXIMUM_ALIGNOF)
#endif
;
typedef unsigned PG_INT128_TYPE uint128
#if defined(pg_attribute_aligned)
pg_attribute_aligned(MAXIMUM_ALIGNOF)
#endif
;
#endif
#endif
/* sig_atomic_t is required by ANSI C, but may be missing on old platforms */
......
......@@ -27,6 +27,9 @@
/* The normal alignment of `long long int', in bytes. */
#undef ALIGNOF_LONG_LONG_INT
/* The normal alignment of `PG_INT128_TYPE', in bytes. */
#undef ALIGNOF_PG_INT128_TYPE
/* The normal alignment of `short', in bytes. */
#undef ALIGNOF_SHORT
......
......@@ -71,6 +71,9 @@
/* The alignment requirement of a `long long int'. */
#define ALIGNOF_LONG_LONG_INT 8
/* The normal alignment of `PG_INT128_TYPE', in bytes. */
#undef ALIGNOF_PG_INT128_TYPE
/* The alignment requirement of a `short'. */
#define ALIGNOF_SHORT 2
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册