diff mbox series

[committed] d: Fix PR96429: Pointer subtraction uses TRUNC_DIV_EXPR

Message ID 20200804082621.2240602-1-ibuclaw@gdcproject.org
State New
Headers show
Series [committed] d: Fix PR96429: Pointer subtraction uses TRUNC_DIV_EXPR | expand

Commit Message

Iain Buclaw Aug. 4, 2020, 8:26 a.m. UTC
Hi,

This patch detects the pattern for pointer substraction in the front-end
AST and uses EXACT_DIV_EXPR rather than TRUNC_DIV_EXPR.

Bootstrapped and regression tested on x86_64-linux-gnu with multilib
configurations -m32/-mx32.  Committed to mainline.

Regards
Iain

---
gcc/d/ChangeLog:

	PR d/96429
	* expr.cc (ExprVisitor::visit (BinExp*)): Use EXACT_DIV_EXPR for
	pointer diff expressions.

gcc/testsuite/ChangeLog:

	PR d/96429
	* gdc.dg/pr96429.d: New test.
---
 gcc/d/expr.cc                  | 12 ++++++++++++
 gcc/testsuite/gdc.dg/pr96429.d | 26 ++++++++++++++++++++++++++
 2 files changed, 38 insertions(+)
 create mode 100644 gcc/testsuite/gdc.dg/pr96429.d
diff mbox series

Patch

diff --git a/gcc/d/expr.cc b/gcc/d/expr.cc
index 20ab49d7b8c..ac3d4aaa171 100644
--- a/gcc/d/expr.cc
+++ b/gcc/d/expr.cc
@@ -620,6 +620,18 @@  public:
 	break;
 
       case TOKdiv:
+	/* Determine if the div expression is a lowered pointer diff operation.
+	   The front-end rewrites `(p1 - p2)' into `(p1 - p2) / stride'.  */
+	if (MinExp *me = e->e1->isMinExp ())
+	  {
+	    if (me->e1->type->ty == Tpointer && me->e2->type->ty == Tpointer
+		&& e->e2->op == TOKint64)
+	      {
+		code = EXACT_DIV_EXPR;
+		break;
+	      }
+	  }
+
 	code = e->e1->type->isintegral ()
 	  ? TRUNC_DIV_EXPR : RDIV_EXPR;
 	break;
diff --git a/gcc/testsuite/gdc.dg/pr96429.d b/gcc/testsuite/gdc.dg/pr96429.d
new file mode 100644
index 00000000000..af096e26b5a
--- /dev/null
+++ b/gcc/testsuite/gdc.dg/pr96429.d
@@ -0,0 +1,26 @@ 
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96429
+// { dg-do compile }
+// { dg-options "-fdump-tree-original" }
+ptrdiff_t subbyte(byte* bp1, byte* bp2)
+{
+    // { dg-final { scan-tree-dump "bp1 - bp2;" "original" } }
+    return bp1 - bp2;
+}
+
+ptrdiff_t subshort(short* sp1, short* sp2)
+{
+    // { dg-final { scan-tree-dump "\\\(sp1 - sp2\\\) /\\\[ex\\\] 2;" "original" } }
+    return sp1 - sp2;
+}
+
+ptrdiff_t subint(int* ip1, int* ip2)
+{
+    // { dg-final { scan-tree-dump "\\\(ip1 - ip2\\\) /\\\[ex\\\] 4;" "original" } }
+    return ip1 - ip2;
+}
+
+ptrdiff_t sublong(long* lp1, long* lp2)
+{
+    // { dg-final { scan-tree-dump "\\\(lp1 - lp2\\\) /\\\[ex\\\] 8;" "original" } }
+    return lp1 - lp2;
+}