瀏覽代碼

* convert n-n mod const into n div const*const, resolves #39615

florian 2 年之前
父節點
當前提交
0ba4cee279
共有 3 個文件被更改,包括 70 次插入0 次删除
  1. 10 0
      compiler/nadd.pas
  2. 30 0
      tests/webtbs/tw39615a.pp
  3. 30 0
      tests/webtbs/tw39615b.pp

+ 10 - 0
compiler/nadd.pas

@@ -958,6 +958,16 @@ implementation
               exit;
           end;
 
+        { convert n - n mod const into n div const*const }
+        if (nodetype=subn) and (right.nodetype=modn) and is_constintnode(taddnode(right).right) and
+          (left.isequal(taddnode(right).left)) and not(might_have_sideeffects(left)) then
+          begin
+            result:=caddnode.create_internal(muln,cmoddivnode.create(divn,left,taddnode(right).right.getcopy),taddnode(right).right);
+            left:=nil;
+            taddnode(right).right:=nil;
+            exit;
+          end;
+
       { both real constants ? }
         if (lt=realconstn) and (rt=realconstn) then
           begin

+ 30 - 0
tests/webtbs/tw39615a.pp

@@ -0,0 +1,30 @@
+{ $define unsigned}
+const
+	Divisor = 17;
+	TestRange = 3 * Divisor;
+var
+	i, x, r1, r2: {$ifdef unsigned} uint32 {$else} int32 {$endif};
+	ok: boolean;
+begin
+	ok := true;
+	for i := {$ifdef unsigned} 0 {$else} -2 * TestRange {$endif} to 2 * TestRange do
+	begin
+	{$ifndef unsigned}
+		if i < -TestRange then
+			x := Low(x) + (i - (-2 * TestRange)) // test [Low(x); Low(x) + TestRange)
+		else
+	{$endif}
+		if i <= TestRange then x := i            // test [-TestRange; TestRange] or [0; TestRange]
+		else x := High(x) - (i - TestRange - 1); // test (High(x) - TestRange; High(x)]
+
+		r1 := x - x mod Divisor;
+		r2 := x div Divisor * Divisor;
+
+		if r1 <> r2 then
+		begin
+			writeln('FAIL: x=', x, ', x - x mod ', Divisor, ' = ', r1, ', x div ', Divisor, ' * ', Divisor, ' = ', r2);
+			ok := false;
+		end;
+	end;
+	if ok then writeln('ok');
+end.

+ 30 - 0
tests/webtbs/tw39615b.pp

@@ -0,0 +1,30 @@
+{$define unsigned}
+const
+	Divisor = 17;
+	TestRange = 3 * Divisor;
+var
+	i, x, r1, r2: {$ifdef unsigned} uint32 {$else} int32 {$endif};
+	ok: boolean;
+begin
+	ok := true;
+	for i := {$ifdef unsigned} 0 {$else} -2 * TestRange {$endif} to 2 * TestRange do
+	begin
+	{$ifndef unsigned}
+		if i < -TestRange then
+			x := Low(x) + (i - (-2 * TestRange)) // test [Low(x); Low(x) + TestRange)
+		else
+	{$endif}
+		if i <= TestRange then x := i            // test [-TestRange; TestRange] or [0; TestRange]
+		else x := High(x) - (i - TestRange - 1); // test (High(x) - TestRange; High(x)]
+
+		r1 := x - x mod Divisor;
+		r2 := x div Divisor * Divisor;
+
+		if r1 <> r2 then
+		begin
+			writeln('FAIL: x=', x, ', x - x mod ', Divisor, ' = ', r1, ', x div ', Divisor, ' * ', Divisor, ' = ', r2);
+			ok := false;
+		end;
+	end;
+	if ok then writeln('ok');
+end.