This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

IPA: Devirtualization versus placement new


Summary: Devirtualization uses type information to determine if a
virtual method is reachable from a call site.  If type information
indicates that it is not, devirt marks the site as unreachable.  I
think this is wrong, and it breaks some programs.  At least, it should
not do this if the user specifies -fno-strict-aliasing.

Consider this class:

class Container {
  void *buffer[5];
public:
  EmbeddedObject *obj() { return (EmbeddedObject*)buffer; }
  Container() { new (buffer) EmbeddedObject(); }
};

Placement new is used to embed an object in a buffer inside another
object.  Its address can be retrieved.  This usage of placement new is
common, and it even appears as the canonical use of placement new in
the in the C++ FAQ at
http://www.parashift.com/c++-faq/placement-new.html.  (I am aware that
this is not strictly legal.  For one thing, the memory at buffer may
not be suitably aligned.  Please bear with me.)

The embedded object is an instance of:

class EmbeddedObject {
public:
  virtual int val() { return 2; }
};

And it is called like this:

extern Container o;
int main() {

  cout << o.obj()->val() << endl;
}

The devirtualization pass looks into the call to val() and the type of
o, decides that there is no type inside o that is compatible with
EmbeddedObject, and inserts a call to __builtin_unreachanble().  As a
result, instead of printing 2, the program does nothing.

I'm not sure what this transformation is supposed to achieve.  It does
nothing for strictly compliant code and it silently breaks non-
compliant code like this.  GCC users would be better off if it were
not done.  At least an error message could be printed instead of silently
failing to generate code.

IMO, this transformation should not be performed when
-fno-strict-aliasing is used.

`-fstrict-aliasing'
     Allow the compiler to assume the strictest aliasing rules
     applicable to the language being compiled.  For C (and C++), this
     activates optimizations based on the type of expressions.

I have appended a suggested patch to this message.

Andrew.


Index: gcc/ipa-devirt.c
===================================================================
--- gcc/ipa-devirt.c	(revision 209656)
+++ gcc/ipa-devirt.c	(working copy)
@@ -1362,8 +1362,9 @@

 		  /* Only type inconsistent programs can have otr_type that is
 		     not part of outer type.  */
-		  if (!contains_type_p (TREE_TYPE (base),
-					context->offset + offset2, *otr_type))
+		  if (flag_strict_aliasing
+		      && !contains_type_p (TREE_TYPE (base),
+					   context->offset + offset2, *otr_type))
 		    {
 		      /* Use OTR_TOKEN = INT_MAX as a marker of probably type inconsistent
 			 code sequences; we arrange the calls to be builtin_unreachable
@@ -1441,7 +1442,8 @@
 	  gcc_assert (!POINTER_TYPE_P (context->outer_type));
 	  /* Only type inconsistent programs can have otr_type that is
 	     not part of outer type.  */
-	  if (!contains_type_p (context->outer_type, context->offset,
+	  if (flag_strict_aliasing
+	      && !contains_type_p (context->outer_type, context->offset,
 			        *otr_type))
 	    {
 	      /* Use OTR_TOKEN = INT_MAX as a marker of probably type inconsistent

Attachment: embed-test.tar
Description: Unix tar archive


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]