bitten by & and |

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

bitten by & and |

Eliot Miranda-2
 
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
Reply | Threaded
Open this post in threaded view
|

Re: bitten by & and |

Bert Freudenberg
 

On 11.01.2011, at 21:00, Eliot Miranda wrote:

Hi All,

    I just got bittenhard (not for the first time) by & and | (implemented both by integers and booleans) 

& and | are not implemented by integers in Squeak. Use bitOr: and bitAnd:.

- Bert -

Reply | Threaded
Open this post in threaded view
|

Re: bitten by & and |

Andreas.Raab
In reply to this post by Eliot Miranda-2
 
I would vote for option

d) Disallow it altogether since it's completely ambiguous and *require*
the use of #or:/bitOr: or #and:/bitAnd:. I.e.,

CCodeGenerator>>generateAmbigousOr: msgNode on: aStream indent: level

        self error: 'Usage of | is ambiguous - use #or: or #bitOr: instead'.

There are only a handful of uses that need to be fixed and the above
would find them very quickly.

Cheers,
   - Andreas


On 1/11/2011 12:00 PM, Eliot Miranda wrote:

>
>
>
>
> 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
Reply | Threaded
Open this post in threaded view
|

Re: bitten by & and |

Igor Stasenko

On 11 January 2011 21:15, Andreas Raab <[hidden email]> wrote:

>
> I would vote for option
>
> d) Disallow it altogether since it's completely ambiguous and *require* the
> use of #or:/bitOr: or #and:/bitAnd:. I.e.,
>
> CCodeGenerator>>generateAmbigousOr: msgNode on: aStream indent: level
>
>        self error: 'Usage of | is ambiguous - use #or: or #bitOr: instead'.
>
> There are only a handful of uses that need to be fixed and the above would
> find them very quickly.
>

+1

rather than trying to find less painful workaround, it is better to
simply bark at each use of it,
and don't generate code until all uses of it will be examined and
replaced with aproppriate or/bitOr/and/bitAnd

Also, for clarity i would even introduce

#define bitAnd(x,y)  ((x) & (y))
#define and(x,y)  ((x) && (y))
#define or(x,y)  ((x) || (y))
#define bitOr(x,y)  ((x) | (y))

and let generate to use these macros instead of &&/&/|/|| . So,in this
way, C code could be more readable :)


> Cheers,
>  - Andreas
>
>
> On 1/11/2011 12:00 PM, Eliot Miranda wrote:
>>
>>
>>
>>
>> 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
>



--
Best regards,
Igor Stasenko AKA sig.
Reply | Threaded
Open this post in threaded view
|

Re: bitten by & and |

Nicolas Cellier

2011/1/11 Igor Stasenko <[hidden email]>:

>
> On 11 January 2011 21:15, Andreas Raab <[hidden email]> wrote:
>>
>> I would vote for option
>>
>> d) Disallow it altogether since it's completely ambiguous and *require* the
>> use of #or:/bitOr: or #and:/bitAnd:. I.e.,
>>
>> CCodeGenerator>>generateAmbigousOr: msgNode on: aStream indent: level
>>
>>        self error: 'Usage of | is ambiguous - use #or: or #bitOr: instead'.
>>
>> There are only a handful of uses that need to be fixed and the above would
>> find them very quickly.
>>
>
> +1
>
> rather than trying to find less painful workaround, it is better to
> simply bark at each use of it,
> and don't generate code until all uses of it will be examined and
> replaced with aproppriate or/bitOr/and/bitAnd
>
> Also, for clarity i would even introduce
>
> #define bitAnd(x,y)  ((x) & (y))
> #define and(x,y)  ((x) && (y))
> #define or(x,y)  ((x) || (y))
> #define bitOr(x,y)  ((x) | (y))
>
> and let generate to use these macros instead of &&/&/|/|| . So,in this
> way, C code could be more readable :)
>

With differences in signed/unsigned promotion to a longer int, I don't
think you'll ever get a readable C ;).

Nicolas

>
>> Cheers,
>>  - Andreas
>>
>>
>> On 1/11/2011 12:00 PM, Eliot Miranda wrote:
>>>
>>>
>>>
>>>
>>> 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
>>
>
>
>
> --
> Best regards,
> Igor Stasenko AKA sig.
>