This patch implements the flag -fassume-sane-operator-new as suggested in
PR110137. When the flag is enabled, it is assumed that operator new does not
modify global memory.
While this patch is not powerful enough to handle the original issue in
PR110035, it allows the optimizer to handle some simpler case (e.g. load from
global memory with fixed address), as demonstrated in the test
sane-operator-new-1.C.
To handle the original issue in PR110035, some other improvement to the
optimizer is needed, which will be sent as subsequent patches.
Bootstrapped and regression tested on x86_64-pc-linux-gnu.
From 14a8604907c89838577ff8560df9a3f9dc2d8afb Mon Sep 17 00:00:00 2001
From: user202729 <user202...@protonmail.com>
Date: Fri, 24 May 2024 17:40:55 +0800
Subject: [PATCH] Implement -fassume-sane-operator-new [PR110137]
PR c++/110137
gcc/c-family/ChangeLog:
* c.opt: New option.
gcc/ChangeLog:
* ira.cc (is_call_operator_new_p): New function.
(may_modify_memory_p): Likewise.
(validate_equiv_mem): Modify to use may_modify_memory_p.
gcc/testsuite/ChangeLog:
* g++.dg/sane-operator-new-1.C: New test.
* g++.dg/sane-operator-new-2.C: New test.
* g++.dg/sane-operator-new-3.C: New test.
---
gcc/c-family/c.opt | 4 ++++
gcc/ira.cc | 23 ++++++++++++++++++++-
gcc/testsuite/g++.dg/sane-operator-new-1.C | 12 +++++++++++
gcc/testsuite/g++.dg/sane-operator-new-2.C | 12 +++++++++++
gcc/testsuite/g++.dg/sane-operator-new-3.C | 24 ++++++++++++++++++++++
5 files changed, 74 insertions(+), 1 deletion(-)
create mode 100644 gcc/testsuite/g++.dg/sane-operator-new-1.C
create mode 100644 gcc/testsuite/g++.dg/sane-operator-new-2.C
create mode 100644 gcc/testsuite/g++.dg/sane-operator-new-3.C
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index fb34c3b7031..20c3ff77ee8 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -1605,6 +1605,10 @@ fasm
C ObjC C++ ObjC++ Var(flag_no_asm, 0)
Recognize the \"asm\" keyword.
+fassume-sane-operator-new
+C++ Optimization Var(flag_assume_sane_operator_new)
+Assume operator new does not have any side effect other than the allocation.
+
; Define extra predefined macros for use in libgcc.
fbuilding-libgcc
C ObjC C++ ObjC++ Undocumented Var(flag_building_libgcc)
diff --git a/gcc/ira.cc b/gcc/ira.cc
index 5642aea3caa..2902853a2bc 100644
--- a/gcc/ira.cc
+++ b/gcc/ira.cc
@@ -3080,6 +3080,27 @@ validate_equiv_mem_from_store (rtx dest, const_rtx set ATTRIBUTE_UNUSED,
static bool equiv_init_varies_p (rtx x);
+static bool is_call_operator_new_p (rtx_insn *insn)
+{
+ if (!CALL_P (insn))
+ return false;
+ tree fn = get_call_fndecl (insn);
+ if (fn == NULL_TREE)
+ return false;
+ return DECL_IS_OPERATOR_NEW_P (fn);
+}
+
+/* Returns true if there is a possibility that INSN may modify memory.
+ If false is returned, the compiler proved INSN never modify memory. */
+static bool may_modify_memory_p (rtx_insn *insn)
+{
+ if (RTL_CONST_OR_PURE_CALL_P (insn))
+ return false;
+ if (flag_assume_sane_operator_new && is_call_operator_new_p (insn))
+ return false;
+ return true;
+}
+
enum valid_equiv { valid_none, valid_combine, valid_reload };
/* Verify that no store between START and the death of REG invalidates
@@ -3123,7 +3144,7 @@ validate_equiv_mem (rtx_insn *start, rtx reg, rtx memref)
been changed and all hell breaks loose. */
ret = valid_combine;
if (!MEM_READONLY_P (memref)
- && (!RTL_CONST_OR_PURE_CALL_P (insn)
+ && (may_modify_memory_p (insn)
|| equiv_init_varies_p (XEXP (memref, 0))))
return valid_none;
}
diff --git a/gcc/testsuite/g++.dg/sane-operator-new-1.C b/gcc/testsuite/g++.dg/sane-operator-new-1.C
new file mode 100644
index 00000000000..de81e1d92b9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/sane-operator-new-1.C
@@ -0,0 +1,12 @@
+/* { dg-do compile { target i?86-*-* x86_64-*-* } } */
+/* { dg-options "-O2 -fassume-sane-operator-new" } */
+int a;
+float *b;
+int
+m ()
+{
+ int x = a;
+ b = new float;
+ return x + a;
+}
+/* { dg-final { scan-assembler-times {a\(%} 1 } } */
diff --git a/gcc/testsuite/g++.dg/sane-operator-new-2.C b/gcc/testsuite/g++.dg/sane-operator-new-2.C
new file mode 100644
index 00000000000..28fe880810e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/sane-operator-new-2.C
@@ -0,0 +1,12 @@
+/* { dg-do compile { target i?86-*-* x86_64-*-* } } */
+/* { dg-options "-O2" } */
+int a;
+float *b;
+int
+m ()
+{
+ int x = a;
+ b = new float;
+ return x + a;
+}
+/* { dg-final { scan-assembler-times {a\(%} 2 } } */
diff --git a/gcc/testsuite/g++.dg/sane-operator-new-3.C b/gcc/testsuite/g++.dg/sane-operator-new-3.C
new file mode 100644
index 00000000000..17e9f0640e3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/sane-operator-new-3.C
@@ -0,0 +1,24 @@
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+typedef __SIZE_TYPE__ size_t;
+extern "C" {
+ void* malloc (size_t);
+ void free (void*);
+ void abort (void);
+}
+int a = 5;
+float *b;
+void *
+__attribute__ ((noinline))
+operator new (size_t n) {
+ a = 70;
+ return malloc (n);
+}
+int
+main ()
+{
+ int x = a;
+ b = new float;
+ if (x + a != 75)
+ abort ();
+}
--
2.34.1