- SPEC_NOUN(val->type) = V_CHAR;
- }
- /* this could be too aggressive:
- 'unsigned char' promotes to 'signed int', so that we can
- reduce it the other way */
- if (IS_INT(val->type) &&
- !SPEC_USIGN(val->type) &&
- !SPEC_LONG(val->type) &&
- SPEC_CVAL(val->type).v_int >= 128 &&
- SPEC_CVAL(val->type).v_int <= 255)
+ /* unsigned operation */
+ TYPE_TARGET_ULONG minValP, maxValP, minValM, maxValM;
+ TYPE_TARGET_ULONG opBitsMask = 0xffffffffu >> (32 - bitsForType (reType));
+
+ if (SPEC_USIGN (lit) && SPEC_USIGN (var))
+ {
+ /* both operands are unsigned, this is easy */
+ minValP = 0;
+ maxValP = 0xffffffffu >> (32 - varBits);
+ /* there's only range, just copy it to 2nd set */
+ minValM = minValP;
+ maxValM = maxValP;
+ }
+ else if (SPEC_USIGN (var))
+ {
+ /* lit is casted from signed to unsigned, e.g.:
+ unsigned u;
+ u == (char) -17
+ -> u == 0xffef'
+ */
+ minValP = 0;
+ maxValP = 0xffffffffu >> (32 - varBits);
+ /* there's only one range, just copy it to 2nd set */
+ minValM = minValP;
+ maxValM = maxValP;
+
+ /* it's an unsigned operation */
+ if ( IS_CHAR (reType)
+ || IS_INT (reType))
+ {
+ /* make signed literal unsigned and
+ limit no of bits to size of return type */
+ litVal = (TYPE_TARGET_ULONG) litVal & opBitsMask;
+ }
+ }
+ else /* SPEC_USIGN (lit) */
+ {
+ /* var is casted from signed to unsigned, e.g.:
+ signed char c;
+ c == (unsigned) -17
+ -> c == 0xffef'
+
+ The possible values after casting var
+ split up in two, nonconsecutive ranges:
+
+ minValP = 0; positive range: 0...127
+ maxValP = 0x7f;
+ minValM = 0xff80; negative range: -128...-1
+ maxValM = 0xffff;
+ */
+
+ /* positive range */
+ minValP = 0;
+ maxValP = 0x7fffffffu >> (32 - varBits);
+
+ /* negative range */
+ minValM = 0xffffffff << (varBits - 1);
+ maxValM = 0xffffffffu; /* -1 */
+ /* limit no of bits to size of return type */
+ minValM &= opBitsMask;
+ maxValM &= opBitsMask;
+ }