1/* PR 16341 */ 2 3#define PART_PRECISION (sizeof (cpp_num_part) * 8) 4 5typedef unsigned int cpp_num_part; 6typedef struct cpp_num cpp_num; 7struct cpp_num 8{ 9 cpp_num_part high; 10 cpp_num_part low; 11 int unsignedp; /* True if value should be treated as unsigned. */ 12 int overflow; /* True if the most recent calculation overflowed. */ 13}; 14 15static int 16num_positive (cpp_num num, unsigned int precision) 17{ 18 if (precision > PART_PRECISION) 19 { 20 precision -= PART_PRECISION; 21 return (num.high & (cpp_num_part) 1 << (precision - 1)) == 0; 22 } 23 24 return (num.low & (cpp_num_part) 1 << (precision - 1)) == 0; 25} 26 27static cpp_num 28num_trim (cpp_num num, unsigned int precision) 29{ 30 if (precision > PART_PRECISION) 31 { 32 precision -= PART_PRECISION; 33 if (precision < PART_PRECISION) 34 num.high &= ((cpp_num_part) 1 << precision) - 1; 35 } 36 else 37 { 38 if (precision < PART_PRECISION) 39 num.low &= ((cpp_num_part) 1 << precision) - 1; 40 num.high = 0; 41 } 42 43 return num; 44} 45 46/* Shift NUM, of width PRECISION, right by N bits. */ 47static cpp_num 48num_rshift (cpp_num num, unsigned int precision, unsigned int n) 49{ 50 cpp_num_part sign_mask; 51 int x = num_positive (num, precision); 52 53 if (num.unsignedp || x) 54 sign_mask = 0; 55 else 56 sign_mask = ~(cpp_num_part) 0; 57 58 if (n >= precision) 59 num.high = num.low = sign_mask; 60 else 61 { 62 /* Sign-extend. */ 63 if (precision < PART_PRECISION) 64 num.high = sign_mask, num.low |= sign_mask << precision; 65 else if (precision < 2 * PART_PRECISION) 66 num.high |= sign_mask << (precision - PART_PRECISION); 67 68 if (n >= PART_PRECISION) 69 { 70 n -= PART_PRECISION; 71 num.low = num.high; 72 num.high = sign_mask; 73 } 74 75 if (n) 76 { 77 num.low = (num.low >> n) | (num.high << (PART_PRECISION - n)); 78 num.high = (num.high >> n) | (sign_mask << (PART_PRECISION - n)); 79 } 80 } 81 82 num = num_trim (num, precision); 83 num.overflow = 0; 84 return num; 85} 86 #define num_zerop(num) ((num.low | num.high) == 0) 87#define num_eq(num1, num2) (num1.low == num2.low && num1.high == num2.high) 88 89cpp_num 90num_lshift (cpp_num num, unsigned int precision, unsigned int n) 91{ 92 if (n >= precision) 93 { 94 num.overflow = !num.unsignedp && !num_zerop (num); 95 num.high = num.low = 0; 96 } 97 else 98 { 99 cpp_num orig; 100 unsigned int m = n; 101 102 orig = num; 103 if (m >= PART_PRECISION) 104 { 105 m -= PART_PRECISION; 106 num.high = num.low; 107 num.low = 0; 108 } 109 if (m) 110 { 111 num.high = (num.high << m) | (num.low >> (PART_PRECISION - m)); 112 num.low <<= m; 113 } 114 num = num_trim (num, precision); 115 116 if (num.unsignedp) 117 num.overflow = 0; 118 else 119 { 120 cpp_num maybe_orig = num_rshift (num, precision, n); 121 num.overflow = !num_eq (orig, maybe_orig); 122 } 123 } 124 125 return num; 126} 127 128unsigned int precision = 64; 129unsigned int n = 16; 130 131cpp_num num = { 0, 3, 0, 0 }; 132 133int main() 134{ 135 cpp_num res = num_lshift (num, 64, n); 136 137 if (res.low != 0x30000) 138 abort (); 139 140 if (res.high != 0) 141 abort (); 142 143 if (res.overflow != 0) 144 abort (); 145 146 exit (0); 147} 148