[Bug c/31734] New: optimizer looses ops for with aliasing

ajrobb at bigfoot dot com gcc-bugzilla@gcc.gnu.org
Sat Apr 28 15:36:00 GMT 2007


The following routine generates takes a value (promoted from float or double to
long double) and generates a two-part mantissa (integer and fraction parts).
With optimisation above -O, the last multiply and addition are not performed. I
can fix this by abusing a union (change #if 0 to #if 1).

typedef struct Double {
  int exponent;
  unsigned mantissa; /**< 100,000,000..999,999,999 */
  unsigned fraction; /**< 0.1 <= fraction < 1 */
} Double;

void scale(Double * out, long double value) {
  typedef struct {
    long double a;
    long double b;
    int scale;
  } Scale;

  static const Scale e3[] =
  { { 1e100L, 1e-100L, 100 }
  , { 1e200L, 1e-200L, 200 }
  , { 1e300L, 1e-300L, 300 }
  };

  static const Scale e2[] =
  { { 1e10L, 1e-10L, 10 }
  , { 1e20L, 1e-20L, 20 }
  , { 1e30L, 1e-30L, 30 }
  , { 1e40L, 1e-40L, 40 }
  , { 1e50L, 1e-50L, 50 }
  , { 1e60L, 1e-60L, 60 }
  , { 1e70L, 1e-70L, 70 }
  , { 1e80L, 1e-80L, 80 }
  , { 1e90L, 1e-90L, 90 }
  };

  static const Scale e1[] =
  { { 1e1L, 1e-1L, 1 }
  , { 1e2L, 1e-2L, 2 }
  , { 1e3L, 1e-3L, 3 }
  , { 1e4L, 1e-4L, 4 }
  , { 1e5L, 1e-5L, 5 }
  , { 1e6L, 1e-6L, 6 }
  , { 1e7L, 1e-7L, 7 }
  , { 1e8L, 1e-8L, 8 }
  , { 1e9L, 1e-9L, 9 }
  };

  typedef struct {
    const Scale * scale;
    const int n;
  } Scales;

  static const Scales scales[] = { { e3, 3 }, { e2, 10 }, { e1, 9 } };

  union {
    unsigned array[3];
    long double value;
  } result = {0,0,0};

  int scale = 0;
  int i;
  if (value < 0) value = -value;

  /* scale 0.1 <= value < 1 */
  if (value != 0) for (i = 0; i < 3; ++i) {
    if (value >= scales[i].scale[0].a) {
      int j = scales[i].n;
      while (--j >= 0) {
        if (value >= scales[i].scale[j].a) {
          value *= scales[i].scale[j].b;
          scale += scales[i].scale[j].scale;
          break;
        }
      }
    }
    else if (value < scales[i].scale[0].b) {
      int j = scales[i].n;
      while (--j >= 0) {
        if (value < scales[i].scale[j].b) {
          value *= scales[i].scale[j].a;
          scale -= scales[i].scale[j].scale;
          break;
        }
      }
    }
  }

  if (value >= 1) {
    value *= 1e-1L;
    scale += 1;
  }
  else if (value < 0.1) {
    value *= 10;
    scale -= 1;
  }

  /* float values for 1e9 and 1u<<31 are exact */
  printf("%.19f\t", (double)value);
  value *= 1e9; /* 1e9 <= value < 1e10 */
  /* fix the position of the decimal point to between words
   * (it also does a good job of rounding)
   */
  value += 2147483648.0f;
#if 0
  /* abuse union to cast (long double) to int[] - but it works */
  result.value = value;
  out->fraction = result.array[0];
  out->mantissa = result.array[1] & 0x7fffffff;
#else
  /* this is odd, using ((int*)&value)[0] fools the optimizer
   * and it omits the previous 2 ops on value!
   */
  out->fraction = ((int*)&value)[0];
  out->mantissa = ((int*)&value)[1] & 0x7fffffff;
#endif
  out->exponent = scale;
}

It appears that because 'value' is not used directly after the last multiply
and add, these operations are dropped by the optimizer. Fails on cygwin, SuSE 8
and SuSE 10.2
gcc version 4.1.2 20061115 (prerelease) (SUSE Linux)
gcc version 3.4.4 (cygming special, gdc 0.12, using dmd 0.125)
gcc version 3.3.3 (SuSE Linux)


-- 
           Summary: optimizer looses ops for with aliasing
           Product: gcc
           Version: 4.1.2
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c
        AssignedTo: unassigned at gcc dot gnu dot org
        ReportedBy: ajrobb at bigfoot dot com
 GCC build triplet: i586-suse-linux
  GCC host triplet: i586-suse-linux
GCC target triplet: i586-suse-linux


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=31734



More information about the Gcc-bugs mailing list