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
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
On 11 January 2011 21:15, Andreas Raab andreas.raab@gmx.de 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
2011/1/11 Igor Stasenko siguctua@gmail.com:
On 11 January 2011 21:15, Andreas Raab andreas.raab@gmx.de 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.
vm-dev@lists.squeakfoundation.org