pastojs: and/or/xor with nativeint, warn nativeint shl/shr

git-svn-id: trunk@41528 -
This commit is contained in:
Mattias Gaertner 2019-02-28 21:57:28 +00:00
parent 119aab42db
commit f6cbe79a0a
4 changed files with 144 additions and 43 deletions

View File

@ -181,7 +181,7 @@ const
nDerivedXMustExtendASubClassY = 3115;
nDefaultPropertyNotAllowedInHelperForX = 3116;
nHelpersCannotBeUsedAsTypes = 3117;
nBitWiseOperationsAre32Bit = 3118;
// free 3118
nImplictConversionUnicodeToAnsi = 3119;
nWrongTypeXInArrayConstructor = 3120;
nUnknownCustomAttributeX = 3121;
@ -315,7 +315,7 @@ resourcestring
sDerivedXMustExtendASubClassY = 'Derived %s must extend a subclass of "%s" or the class itself';
sDefaultPropertyNotAllowedInHelperForX = 'Default property not allowed in helper for %s';
sHelpersCannotBeUsedAsTypes = 'helpers cannot be used as types';
sBitWiseOperationsAre32Bit = 'Bitwise operations are 32-bit';
// was 3118
sImplictConversionUnicodeToAnsi = 'Implicit string type conversion with potential data loss from "UnicodeString" to "AnsiString"';
sWrongTypeXInArrayConstructor = 'Wrong type "%s" in array constructor';
sUnknownCustomAttributeX = 'Unknown custom attribute "%s"';

View File

@ -520,6 +520,7 @@ const
nCantCallExtBracketAccessor = 4025;
nJSNewNotSupported = 4026;
nHelperClassMethodForExtClassMustBeStatic = 4027;
nBitWiseOperationIs32Bit = 4028;
// resourcestring patterns of messages
resourcestring
sPasElementNotSupported = 'Pascal element not supported: %s';
@ -549,6 +550,7 @@ resourcestring
sCantCallExtBracketAccessor = 'cannot call external bracket accessor, use a property instead';
sJSNewNotSupported = 'Pascal class does not support the "new" constructor';
sHelperClassMethodForExtClassMustBeStatic = 'Helper class method for external class must be static';
sBitWiseOperationIs32Bit = 'Bitwise operation is 32-bit';
const
ExtClassBracketAccessor = '[]'; // external name '[]' marks the array param getter/setter
@ -566,6 +568,9 @@ type
pbifnArray_Static_Clone,
pbifnAs,
pbifnAsExt,
pbifnBitwiseNativeIntAnd,
pbifnBitwiseNativeIntOr,
pbifnBitwiseNativeIntXor,
pbifnCheckMethodCall,
pbifnCheckVersion,
pbifnClassInstanceFree,
@ -725,6 +730,9 @@ const
'$clone',
'as', // rtl.as
'asExt', // rtl.asExt
'and', // pbifnBitwiseNativeIntAnd,
'or', // pbifnBitwiseNativeIntOr,
'xor', // pbifnBitwiseNativeIntXor,
'checkMethodCall',
'checkVersion',
'$destroy',
@ -6812,9 +6820,7 @@ begin
Result:=Call;
exit;
end;
eopAnd,
eopOr,
eopXor:
eopAnd:
begin
if aResolver<>nil then
begin
@ -6823,26 +6829,74 @@ begin
if UseBitwiseOp
and (LeftResolved.BaseType in [btIntDouble,btUIntDouble])
and (RightResolved.BaseType in [btIntDouble,btUIntDouble]) then
aResolver.LogMsg(20190124233439,mtWarning,nBitWiseOperationsAre32Bit,
sBitWiseOperationsAre32Bit,[],El);
begin
Call:=CreateCallExpression(El);
Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnBitwiseNativeIntAnd)]);
Call.AddArg(A);
Call.AddArg(B);
Result:=Call;
exit;
end;
end
else
UseBitwiseOp:=(GetExpressionValueType(El.left,AContext)=jstNumber)
or (GetExpressionValueType(El.right,AContext)=jstNumber);
if UseBitwiseOp then
Case El.OpCode of
eopAnd : C:=TJSBitwiseAndExpression;
eopOr : C:=TJSBitwiseOrExpression;
eopXor : C:=TJSBitwiseXOrExpression;
C:=TJSBitwiseAndExpression
else
C:=TJSLogicalAndExpression;
end;
eopOr:
begin
if aResolver<>nil then
begin
UseBitwiseOp:=((LeftResolved.BaseType in btAllJSInteger)
or (RightResolved.BaseType in btAllJSInteger));
if UseBitwiseOp
and ((LeftResolved.BaseType in [btIntDouble,btUIntDouble])
or (RightResolved.BaseType in [btIntDouble,btUIntDouble])) then
begin
Call:=CreateCallExpression(El);
Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnBitwiseNativeIntOr)]);
Call.AddArg(A);
Call.AddArg(B);
Result:=Call;
exit;
end;
end
else
Case El.OpCode of
eopAnd : C:=TJSLogicalAndExpression;
eopOr : C:=TJSLogicalOrExpression;
eopXor : C:=TJSBitwiseXOrExpression;
else
DoError(20161024191234,nBinaryOpcodeNotSupported,sBinaryOpcodeNotSupported,['logical XOR'],El);
end;
UseBitwiseOp:=(GetExpressionValueType(El.left,AContext)=jstNumber)
or (GetExpressionValueType(El.right,AContext)=jstNumber);
if UseBitwiseOp then
C:=TJSBitwiseOrExpression
else
C:=TJSLogicalOrExpression;
end;
eopXor:
begin
if aResolver<>nil then
begin
UseBitwiseOp:=((LeftResolved.BaseType in btAllJSInteger)
or (RightResolved.BaseType in btAllJSInteger));
if UseBitwiseOp
and ((LeftResolved.BaseType in [btIntDouble,btUIntDouble])
or (RightResolved.BaseType in [btIntDouble,btUIntDouble])) then
begin
Call:=CreateCallExpression(El);
Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnBitwiseNativeIntXor)]);
Call.AddArg(A);
Call.AddArg(B);
Result:=Call;
exit;
end;
end
else
UseBitwiseOp:=(GetExpressionValueType(El.left,AContext)=jstNumber)
or (GetExpressionValueType(El.right,AContext)=jstNumber);
if UseBitwiseOp then
C:=TJSBitwiseXOrExpression
else
C:=TJSBitwiseXOrExpression;
end;
eopPower:
begin
@ -6851,7 +6905,7 @@ begin
Call.AddArg(A);
Call.AddArg(B);
Result:=Call;
end
end;
else
if C=nil then
DoError(20161024191244,nBinaryOpcodeNotSupported,sBinaryOpcodeNotSupported,[OpcodeStrings[El.OpCode]],El);
@ -6863,11 +6917,17 @@ begin
R.B:=B; B:=nil;
Result:=R;
if El.OpCode=eopDiv then
case El.OpCode of
eopDiv:
begin
// convert "a div b" to "Math.floor(a/b)"
Result:=CreateMathFloor(El,Result);
end;
eopShl,eopShr:
if (aResolver<>nil) and (LeftResolved.BaseType in [btIntDouble,btUIntDouble]) then
aResolver.LogMsg(20190228220225,mtWarning,nBitWiseOperationIs32Bit,
sBitWiseOperationIs32Bit,[],El);
end;
if (bsOverflowChecks in AContext.ScannerBoolSwitches) and (aResolver<>nil) then
case El.OpCode of

View File

@ -263,7 +263,7 @@ type
Procedure TestInteger;
Procedure TestIntegerRange;
Procedure TestIntegerTypecasts;
Procedure TestBitwiseAndNativeIntWarn;
Procedure TestBitwiseShlNativeIntWarn;
Procedure TestCurrency;
Procedure TestForBoolDo;
Procedure TestForIntDo;
@ -3080,24 +3080,36 @@ end;
procedure TTestModule.TestBitwiseOperators;
begin
StartProgram(false);
Add('var');
Add(' vA,vB,vC:longint;');
Add('begin');
Add(' va:=vb and vc;');
Add(' va:=vb or vc;');
Add(' va:=vb xor vc;');
Add(' va:=vb shl vc;');
Add(' va:=vb shr vc;');
Add(' va:=3 and vc;');
Add(' va:=(vb and vc) or (va and vb);');
Add(' va:=not vb;');
Add([
'var',
' vA,vB,vC:longint;',
' X,Y,Z: nativeint;',
'begin',
' va:=vb and vc;',
' va:=vb or vc;',
' va:=vb xor vc;',
' va:=vb shl vc;',
' va:=vb shr vc;',
' va:=3 and vc;',
' va:=(vb and vc) or (va and vb);',
' va:=not vb;',
' X:=Y and Z;',
' X:=Y and va;',
' X:=Y or Z;',
' X:=Y or va;',
' X:=Y xor Z;',
' X:=Y xor va;',
'']);
ConvertProgram;
CheckSource('TestBitwiseOperators',
LinesToStr([ // statements
'this.vA = 0;',
'this.vB = 0;',
'this.vC = 0;'
]),
'this.vC = 0;',
'this.X = 0;',
'this.Y = 0;',
'this.Z = 0;',
'']),
LinesToStr([ // this.$main
'$mod.vA = $mod.vB & $mod.vC;',
'$mod.vA = $mod.vB | $mod.vC;',
@ -3106,8 +3118,14 @@ begin
'$mod.vA = $mod.vB >>> $mod.vC;',
'$mod.vA = 3 & $mod.vC;',
'$mod.vA = ($mod.vB & $mod.vC) | ($mod.vA & $mod.vB);',
'$mod.vA = ~$mod.vB;'
]));
'$mod.vA = ~$mod.vB;',
'$mod.X = rtl.and($mod.Y, $mod.Z);',
'$mod.X = $mod.Y & $mod.vA;',
'$mod.X = rtl.or($mod.Y, $mod.Z);',
'$mod.X = rtl.or($mod.Y, $mod.vA);',
'$mod.X = rtl.xor($mod.Y, $mod.Z);',
'$mod.X = rtl.xor($mod.Y, $mod.vA);',
'']));
end;
procedure TTestModule.TestPrgProcVar;
@ -6414,25 +6432,24 @@ begin
'']));
end;
procedure TTestModule.TestBitwiseAndNativeIntWarn;
procedure TTestModule.TestBitwiseShlNativeIntWarn;
begin
StartProgram(false);
Add([
'var',
' i,j: nativeint;',
' i: nativeint;',
'begin',
' i:=i and j;',
' i:=i shl 3;',
'']);
ConvertProgram;
CheckSource('TestBitwiseAndNativeIntWarn',
CheckSource('TestBitwiseShlNativeIntWarn',
LinesToStr([
'this.i = 0;',
'this.j = 0;',
'']),
LinesToStr([
'$mod.i = $mod.i & $mod.j;',
'$mod.i = $mod.i << 3;',
'']));
CheckHint(mtWarning,nBitWiseOperationsAre32Bit,sBitWiseOperationsAre32Bit);
CheckHint(mtWarning,nBitWiseOperationIs32Bit,sBitWiseOperationIs32Bit);
end;
procedure TTestModule.TestCurrency;

View File

@ -1065,6 +1065,30 @@ var rtl = {
return 0;
},
and: function(a,b){
var hi = 0x80000000;
var low = 0x7fffffff;
var h = (a / hi) & (b / hi);
var l = (a & low) & (b & low);
return h*hi + l;
},
or: function(a,b){
var hi = 0x80000000;
var low = 0x7fffffff;
var h = (a / hi) | (b / hi);
var l = (a & low) | (b & low);
return h*hi + l;
},
xor: function(a,b){
var hi = 0x80000000;
var low = 0x7fffffff;
var h = (a / hi) ^ (b / hi);
var l = (a & low) ^ (b & low);
return h*hi + l;
},
initRTTI: function(){
if (rtl.debug_rtti) rtl.debug('initRTTI');