[Vm-dev] bitten by & and |

Eliot Miranda eliot.miranda at gmail.com
Tue Jan 11 20:00:55 UTC 2011


Hi All,

    I just got bittenhard (not for the first time) by & and | (implemented
both by integers and booleans) being translated into && (== and:) and || (==
or:).  So the following in constant folding in the
StackToRegisterMappingCogit

(argIsInt and: [rcvrIsInt]) ifTrue:
[rcvrInt := objectMemory integerValueOf: rcvrInt.
 argInt := objectMemory integerValueOf: argInt.
 primDescriptor opcode caseOf: {
[AddRR] -> [result := rcvrInt + argInt].
[SubRR] -> [result := rcvrInt - argInt].
[AndRR] -> [result := rcvrInt &: argInt].
[OrRR] -> [result := rcvrInt | argInt] }.
(objectMemory isIntegerValue: result) ifTrue:
["Must annotate the bytecode for correct pc mapping."
self annotateBytecode: self Label.
^self ssPop: 2; ssPushConstant: (objectMemory integerObjectOf: result)].
^self genSpecialSelectorSend].

produced valid results in the simulator, but was translated to

    if (argIsInt
     && (rcvrIsInt)) {
        rcvrInt = (rcvrInt >> 1);
        argInt = (argInt >> 1);

        switch ((primDescriptor->opcode)) {
        case AddRR:
                        result = rcvrInt + argInt;
            break;
        case SubRR:
                        result = rcvrInt - argInt;
            break;
        case AndRR:
                        result = rcvrInt && argInt;
            break;
        case OrRR:
                        result = rcvrInt || argInt;
            break;
        default:
            error("Case not found and no otherwise clause");
        }
        if (isIntegerValue(result)) {
            annotateBytecode(gLabel());
            return ssPop(2),ssPushConstant(((result << 1) | 1));
        }
        return genSpecialSelectorSend();
    }

and so e.g. 16r4000 bitOr: 16r8000 evaluated to 1, not 49152.

Three approaches come to mind,
a) emit a warning when & and | are used with variables and/or literals as
opposed to message sends, e.g. warn for 1 | 2, var | var et al, but not for
(a > b) | (b > c) et al
b) translate | to | and & to &
c) translate expr | expr to expr || expr and expr & expr to expr && expr,
but translate varOrLiteral | anything to varOrLiteral | anything and
varOrLiteral & anything to varOrLiteral & anything, and vice verse.

I'm for b) since a relational expression such as a > 1 is defined in C to be
either 1 or 0, and so in C (oneOrZero | oneOrZero) == (oneOrZero
|| oneOrZero) and (oneOrZero & oneOrZero) == (oneOrZero && oneOrZero).

Thoughts, opinions?

best (hurting),
Eliot
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.squeakfoundation.org/pipermail/vm-dev/attachments/20110111/465b153f/attachment.htm


More information about the Vm-dev mailing list