r281693 - Alter the iOS/tvOS ARM64 C++ ABI to ignore the upper half of the

John McCall via cfe-commits cfe-commits at lists.llvm.org
Thu Sep 15 19:40:45 PDT 2016


Author: rjmccall
Date: Thu Sep 15 21:40:45 2016
New Revision: 281693

URL: http://llvm.org/viewvc/llvm-project?rev=281693&view=rev
Log:
Alter the iOS/tvOS ARM64 C++ ABI to ignore the upper half of the
virtual table offset in a member function pointer.

We are reserving this space for future ABI use relating to alternative
v-table configurations.  In the meantime, continue to zero-initialize
this space when actually emitting a member pointer literal.

This will successfully interoperate with existing compilers.
Future versions of the compiler may place additional data in
this location, and at that point, code emitted by compilers
prior to this patch will fail if exposed to such a member pointer.
This is therefore a somewhat hard ABI break.  However, because
it is limited to an uncommon case of an uncommon language feature,
and especially because interoperation with the standard library
does not depend on member pointers, we believe that with a
sufficiently advance compiler change the impact of this break
will be minimal in practice.

Modified:
    cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
    cfe/trunk/test/CodeGenCXX/arm64.cpp

Modified: cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp?rev=281693&r1=281692&r2=281693&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp (original)
+++ cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp Thu Sep 15 21:40:45 2016
@@ -45,6 +45,7 @@ class ItaniumCXXABI : public CodeGen::CG
 protected:
   bool UseARMMethodPtrABI;
   bool UseARMGuardVarABI;
+  bool Use32BitVTableOffsetABI;
 
   ItaniumMangleContext &getMangleContext() {
     return cast<ItaniumMangleContext>(CodeGen::CGCXXABI::getMangleContext());
@@ -55,7 +56,8 @@ public:
                 bool UseARMMethodPtrABI = false,
                 bool UseARMGuardVarABI = false) :
     CGCXXABI(CGM), UseARMMethodPtrABI(UseARMMethodPtrABI),
-    UseARMGuardVarABI(UseARMGuardVarABI) { }
+    UseARMGuardVarABI(UseARMGuardVarABI),
+    Use32BitVTableOffsetABI(false) { }
 
   bool classifyReturnType(CGFunctionInfo &FI) const override;
 
@@ -425,7 +427,9 @@ public:
 
 class iOS64CXXABI : public ARMCXXABI {
 public:
-  iOS64CXXABI(CodeGen::CodeGenModule &CGM) : ARMCXXABI(CGM) {}
+  iOS64CXXABI(CodeGen::CodeGenModule &CGM) : ARMCXXABI(CGM) {
+    Use32BitVTableOffsetABI = true;
+  }
 
   // ARM64 libraries are prepared for non-unique RTTI.
   bool shouldRTTIBeUnique() const override { return false; }
@@ -579,9 +583,15 @@ llvm::Value *ItaniumCXXABI::EmitLoadOfMe
     CGF.GetVTablePtr(Address(This, VTablePtrAlign), VTableTy, RD);
 
   // Apply the offset.
+  // On ARM64, to reserve extra space in virtual member function pointers,
+  // we only pay attention to the low 32 bits of the offset.
   llvm::Value *VTableOffset = FnAsInt;
   if (!UseARMMethodPtrABI)
     VTableOffset = Builder.CreateSub(VTableOffset, ptrdiff_1);
+  if (Use32BitVTableOffsetABI) {
+    VTableOffset = Builder.CreateTrunc(VTableOffset, CGF.Int32Ty);
+    VTableOffset = Builder.CreateZExt(VTableOffset, CGM.PtrDiffTy);
+  }
   VTable = Builder.CreateGEP(VTable, VTableOffset);
 
   // Load the virtual function to call.

Modified: cfe/trunk/test/CodeGenCXX/arm64.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/arm64.cpp?rev=281693&r1=281692&r2=281693&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/arm64.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/arm64.cpp Thu Sep 15 21:40:45 2016
@@ -84,3 +84,39 @@ namespace test2 {
   // CHECK-GLOBALS-DAG: @_ZTIN5test21EIiEE = weak_odr constant { {{.*}}, i8* inttoptr (i64 add (i64 ptrtoint ([14 x i8]* @_ZTSN5test21EIiEE to i64), i64 -9223372036854775808) to i8*) }
 
 }
+
+// ARM64 reserves the top half of the vtable offset in virtual
+// member pointers.
+namespace test3 {
+  struct A {
+    virtual void foo();
+    virtual void bar();
+  };
+
+  // The offset half of the pointer is still initialized to zero.
+  // CHECK-GLOBALS-DAG: @_ZN5test34mptrE = global { i64, i64 } { i64 0, i64 1 }
+  void (A::*mptr)() = &A::foo;
+
+  // CHECK-LABEL: define void @_ZN5test34testEv()
+  // CHECK:       [[TEMP:%.*]] = alloca [[A:.*]], align 8
+  // CHECK:       [[MEMPTR:%.*]] = load { i64, i64 }, { i64, i64 }* @_ZN5test34mptrE, align 8
+  // CHECK:       [[ADJUST_AND_IS_VIRTUAL:%.*]] = extractvalue { i64, i64 } [[MEMPTR]], 1
+  // CHECK:       [[ADJUST:%.*]] = ashr i64 [[ADJUST_AND_IS_VIRTUAL]], 1
+  // CHECK:       [[T0:%.*]] = bitcast [[A]]* [[TEMP]] to i8*
+  // CHECK:       [[T1:%.*]] = getelementptr inbounds i8, i8* [[T0]], i64 [[ADJUST]]
+  // CHECK:       [[ADJUSTED:%.*]] = bitcast i8* [[T1]] to [[A]]*
+  // CHECK:       [[MEMBER:%.*]] = extractvalue { i64, i64 } [[MEMPTR]], 0
+  // CHECK:       [[T0:%.*]] = and i64 [[ADJUST_AND_IS_VIRTUAL]], 1
+  // CHECK:       [[IS_VIRTUAL:%.*]] = icmp ne i64 [[T0]], 0
+  // CHECK:       br i1 [[IS_VIRTUAL]],
+  // CHECK:       [[T0:%.*]] = bitcast [[A]]* [[ADJUSTED]] to i8**
+  // CHECK:       [[VPTR:%.*]] = load i8*, i8** [[T0]], align 8
+  // CHECK:       [[TRUNC:%.*]] = trunc i64 [[MEMBER]] to i32
+  // CHECK:       [[ZEXT:%.*]] = zext i32 [[TRUNC]] to i64
+  // CHECK:       [[T0:%.*]] = getelementptr i8, i8* [[VPTR]], i64 [[ZEXT]]
+  // CHECK:       [[T1:%.*]] = bitcast i8* [[T0]] to void ([[A]]*)**
+  // CHECK:       load void ([[A]]*)*, void ([[A]]*)** [[T1]],
+  void test() {
+    (A().*mptr)();
+  }
+}




More information about the cfe-commits mailing list