return cast<llvm::Function>(GetOrCreateLLVMFunction(Name, FTy, GD));
}
-llvm::Constant *
-CodeGenModule::GetCXXMemberFunctionPointerValue(const CXXMethodDecl *MD) {
- assert(MD->isInstance() && "Member function must not be static!");
-
- MD = MD->getCanonicalDecl();
-
- const llvm::Type *PtrDiffTy = Types.ConvertType(Context.getPointerDiffType());
-
- // Get the function pointer (or index if this is a virtual function).
- if (MD->isVirtual()) {
- uint64_t Index = VTables.getMethodVTableIndex(MD);
-
- // FIXME: We shouldn't use / 8 here.
- uint64_t PointerWidthInBytes = Context.Target.getPointerWidth(0) / 8;
-
- // Itanium C++ ABI 2.3:
- // For a non-virtual function, this field is a simple function pointer.
- // For a virtual function, it is 1 plus the virtual table offset
- // (in bytes) of the function, represented as a ptrdiff_t.
- return llvm::ConstantInt::get(PtrDiffTy, (Index * PointerWidthInBytes) + 1);
- }
-
- const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
- const llvm::Type *Ty;
- // Check whether the function has a computable LLVM signature.
- if (!CodeGenTypes::VerifyFuncTypeComplete(FPT)) {
- // The function has a computable LLVM signature; use the correct type.
- Ty = Types.GetFunctionType(Types.getFunctionInfo(MD), FPT->isVariadic());
- } else {
- // Use an arbitrary non-function type to tell GetAddrOfFunction that the
- // function type is incomplete.
- Ty = PtrDiffTy;
- }
-
- llvm::Constant *FuncPtr = GetAddrOfFunction(MD, Ty);
- return llvm::ConstantExpr::getPtrToInt(FuncPtr, PtrDiffTy);
-}
-
static llvm::Value *BuildVirtualCall(CodeGenFunction &CGF, uint64_t VTableIndex,
llvm::Value *This, const llvm::Type *Ty) {
Ty = Ty->getPointerTo()->getPointerTo()->getPointerTo();
ErrorUnsupportedABI(CGF, "null member function pointers");
}
+void CGCXXABI::EmitMemberFunctionPointer(CodeGenFunction &CGF,
+ const CXXMethodDecl *MD,
+ llvm::Value *DestPtr,
+ bool VolatileDest) {
+ ErrorUnsupportedABI(CGF, "member function pointers");
+}
+
llvm::Constant *
CGCXXABI::EmitMemberFunctionPointerConversion(llvm::Constant *C,
const CastExpr *E) {
return 0;
}
+llvm::Constant *CGCXXABI::EmitMemberFunctionPointer(const CXXMethodDecl *MD) {
+ return 0;
+}
+
bool CGCXXABI::RequiresNonZeroInitializer(QualType T) {
return false;
}
namespace clang {
class CastExpr;
+ class CXXMethodDecl;
class CXXRecordDecl;
class MemberPointerType;
class QualType;
virtual llvm::Constant *
EmitNullMemberFunctionPointer(const MemberPointerType *MPT);
+
+ virtual llvm::Constant *EmitMemberFunctionPointer(const CXXMethodDecl *MD);
+ virtual void EmitMemberFunctionPointer(CodeGenFunction &CGF,
+ const CXXMethodDecl *MD,
+ llvm::Value *DestPtr,
+ bool VolatileDest);
};
/// Creates an instance of a C++ ABI class.
void AggExprEmitter::VisitUnaryAddrOf(const UnaryOperator *E) {
// We have a member function pointer.
- const MemberPointerType *MPT = E->getType()->getAs<MemberPointerType>();
- (void) MPT;
- assert(MPT->getPointeeType()->isFunctionProtoType() &&
+ assert(E->getType()->getAs<MemberPointerType>()
+ ->getPointeeType()->isFunctionProtoType() &&
"Unexpected member pointer type!");
// The creation of member function pointers has no side effects; if
return;
const DeclRefExpr *DRE = cast<DeclRefExpr>(E->getSubExpr());
- const CXXMethodDecl *MD =
- cast<CXXMethodDecl>(DRE->getDecl())->getCanonicalDecl();
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(DRE->getDecl());
- const llvm::Type *PtrDiffTy =
- CGF.ConvertType(CGF.getContext().getPointerDiffType());
-
- llvm::Value *DstPtr = Builder.CreateStructGEP(DestPtr, 0, "dst.ptr");
- llvm::Value *FuncPtr = CGF.CGM.GetCXXMemberFunctionPointerValue(MD);
- Builder.CreateStore(FuncPtr, DstPtr, VolatileDest);
-
- llvm::Value *AdjPtr = Builder.CreateStructGEP(DestPtr, 1, "dst.adj");
- // The adjustment will always be 0.
- Builder.CreateStore(llvm::ConstantInt::get(PtrDiffTy, 0), AdjPtr,
- VolatileDest);
+ CGF.CGM.getCXXABI().EmitMemberFunctionPointer(CGF, MD, DestPtr, VolatileDest);
}
void AggExprEmitter::VisitStmtExpr(const StmtExpr *E) {
}
llvm::Constant *EmitMemberFunctionPointer(CXXMethodDecl *MD) {
- assert(MD->isInstance() && "Member function must not be static!");
-
- MD = MD->getCanonicalDecl();
-
- const llvm::Type *PtrDiffTy =
- CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType());
-
- llvm::Constant *Values[2];
-
- Values[0] = CGM.GetCXXMemberFunctionPointerValue(MD);
-
- // The adjustment will always be 0.
- Values[1] = llvm::ConstantInt::get(PtrDiffTy, 0);
-
- return llvm::ConstantStruct::get(CGM.getLLVMContext(),
- Values, 2, /*Packed=*/false);
+ return CGM.getCXXABI().EmitMemberFunctionPointer(MD);
}
llvm::Constant *VisitUnaryAddrOf(UnaryOperator *E) {
llvm::GlobalValue *GetAddrOfCXXDestructor(const CXXDestructorDecl *D,
CXXDtorType Type);
- // GetCXXMemberFunctionPointerValue - Given a method declaration, return the
- // integer used in a member function pointer to refer to that value.
- llvm::Constant *GetCXXMemberFunctionPointerValue(const CXXMethodDecl *MD);
-
/// getBuiltinLibFunction - Given a builtin id for a function like
/// "__builtin_fabsf", return a Function* for "fabsf".
llvm::Value *getBuiltinLibFunction(const FunctionDecl *FD,
llvm::Constant *EmitNullMemberFunctionPointer(const MemberPointerType *MPT);
+ void EmitMemberFunctionPointer(CodeGenFunction &CGF,
+ const CXXMethodDecl *MD,
+ llvm::Value *Dest,
+ bool VolatileDest);
+
+ llvm::Constant *EmitMemberFunctionPointer(const CXXMethodDecl *MD);
+
+private:
+ void GetMemberFunctionPointer(const CXXMethodDecl *MD,
+ llvm::Constant *(&Array)[2]);
};
class ARMCXXABI : public ItaniumCXXABI {
return new ARMCXXABI(CGM);
}
+void ItaniumCXXABI::GetMemberFunctionPointer(const CXXMethodDecl *MD,
+ llvm::Constant *(&MemPtr)[2]) {
+ assert(MD->isInstance() && "Member function must not be static!");
+
+ MD = MD->getCanonicalDecl();
+
+ CodeGenTypes &Types = CGM.getTypes();
+ const llvm::Type *ptrdiff_t =
+ Types.ConvertType(CGM.getContext().getPointerDiffType());
+
+ // Get the function pointer (or index if this is a virtual function).
+ if (MD->isVirtual()) {
+ uint64_t Index = CGM.getVTables().getMethodVTableIndex(MD);
+
+ // FIXME: We shouldn't use / 8 here.
+ uint64_t PointerWidthInBytes =
+ CGM.getContext().Target.getPointerWidth(0) / 8;
+ uint64_t VTableOffset = (Index * PointerWidthInBytes);
+
+ if (IsARM) {
+ // ARM C++ ABI 3.2.1:
+ // This ABI specifies that adj contains twice the this
+ // adjustment, plus 1 if the member function is virtual. The
+ // least significant bit of adj then makes exactly the same
+ // discrimination as the least significant bit of ptr does for
+ // Itanium.
+ MemPtr[0] = llvm::ConstantInt::get(ptrdiff_t, VTableOffset);
+ MemPtr[1] = llvm::ConstantInt::get(ptrdiff_t, 1);
+ } else {
+ // Itanium C++ ABI 2.3:
+ // For a virtual function, [the pointer field] is 1 plus the
+ // virtual table offset (in bytes) of the function,
+ // represented as a ptrdiff_t.
+ MemPtr[0] = llvm::ConstantInt::get(ptrdiff_t, VTableOffset + 1);
+ MemPtr[1] = llvm::ConstantInt::get(ptrdiff_t, 0);
+ }
+ } else {
+ const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
+ const llvm::Type *Ty;
+ // Check whether the function has a computable LLVM signature.
+ if (!CodeGenTypes::VerifyFuncTypeComplete(FPT)) {
+ // The function has a computable LLVM signature; use the correct type.
+ Ty = Types.GetFunctionType(Types.getFunctionInfo(MD), FPT->isVariadic());
+ } else {
+ // Use an arbitrary non-function type to tell GetAddrOfFunction that the
+ // function type is incomplete.
+ Ty = ptrdiff_t;
+ }
+
+ llvm::Constant *Addr = CGM.GetAddrOfFunction(MD, Ty);
+ MemPtr[0] = llvm::ConstantExpr::getPtrToInt(Addr, ptrdiff_t);
+ MemPtr[1] = llvm::ConstantInt::get(ptrdiff_t, 0);
+ }
+}
+
+
/// In the Itanium and ARM ABIs, method pointers have the form:
/// struct { ptrdiff_t ptr; ptrdiff_t adj; } memptr;
///
CGF.CGM.GetNonVirtualBaseClassOffset(DerivedDecl,
E->path_begin(),
E->path_end())) {
+ // The this-adjustment is left-shifted by 1 on ARM.
+ if (IsARM) {
+ uint64_t Offset = cast<llvm::ConstantInt>(Adj)->getZExtValue();
+ Offset <<= 1;
+ Adj = llvm::ConstantInt::get(Adj->getType(), Offset);
+ }
+
if (DerivedToBase)
SrcAdj = Builder.CreateSub(SrcAdj, Adj, "adj");
else
// If there's no offset, we're done.
if (!Offset) return C;
+ // The this-adjustment is left-shifted by 1 on ARM.
+ if (IsARM) {
+ uint64_t OffsetV = cast<llvm::ConstantInt>(Offset)->getZExtValue();
+ OffsetV <<= 1;
+ Offset = llvm::ConstantInt::get(Offset->getType(), OffsetV);
+ }
+
llvm::ConstantStruct *CS = cast<llvm::ConstantStruct>(C);
llvm::Constant *Values[2] = {
return CGM.EmitNullConstant(QualType(MPT, 0));
}
+llvm::Constant *
+ItaniumCXXABI::EmitMemberFunctionPointer(const CXXMethodDecl *MD) {
+ llvm::Constant *Values[2];
+ GetMemberFunctionPointer(MD, Values);
+
+ return llvm::ConstantStruct::get(CGM.getLLVMContext(),
+ Values, 2, /*Packed=*/false);
+}
+
+void ItaniumCXXABI::EmitMemberFunctionPointer(CodeGenFunction &CGF,
+ const CXXMethodDecl *MD,
+ llvm::Value *DestPtr,
+ bool VolatileDest) {
+ llvm::Constant *Values[2];
+ GetMemberFunctionPointer(MD, Values);
+
+ CGBuilderTy &Builder = CGF.Builder;
+
+ llvm::Value *DstPtr = Builder.CreateStructGEP(DestPtr, 0, "memptr.ptr");
+ Builder.CreateStore(Values[0], DstPtr, VolatileDest);
+
+ llvm::Value *AdjPtr = Builder.CreateStructGEP(DestPtr, 1, "memptr.adj");
+ Builder.CreateStore(Values[1], AdjPtr, VolatileDest);
+}
+
+
bool ItaniumCXXABI::RequiresNonZeroInitializer(QualType T) {
return CGM.getTypes().ContainsPointerToDataMember(T);
}
// FIXME: This is broken, we should store the TargetOptions in the AST file.
TargetOptions TargetOpts;
TargetOpts.ABI = "";
- TargetOpts.CXXABI = "itanium";
+ TargetOpts.CXXABI = "";
TargetOpts.CPU = "";
TargetOpts.Features.clear();
TargetOpts.Triple = TargetTriple;
Res.push_back("-target-linker-version");
Res.push_back(Opts.LinkerVersion);
}
- Res.push_back("-cxx-abi");
- Res.push_back(Opts.CXXABI);
+ if (!Opts.CXXABI.empty()) {
+ Res.push_back("-cxx-abi");
+ Res.push_back(Opts.CXXABI);
+ }
for (unsigned i = 0, e = Opts.Features.size(); i != e; ++i) {
Res.push_back("-target-feature");
Res.push_back(Opts.Features[i]);
// Use the host triple if unspecified.
if (Opts.Triple.empty())
Opts.Triple = llvm::sys::getHostTriple();
-
- // Use the Itanium C++ ABI if unspecified.
- if (Opts.CXXABI.empty())
- Opts.CXXABI = "itanium";
}
//
// RUN: %clang_cc1 %s -emit-llvm -o - -triple=x86_64-apple-darwin9 | FileCheck %s
// RUN: %clang_cc1 %s -emit-llvm -o - -triple=i386-apple-darwin9 | FileCheck -check-prefix LP32 %s
+// RUN: %clang_cc1 %s -emit-llvm -o - -triple=armv7-unknown-unknown | FileCheck -check-prefix ARM %s
struct A { int a; void f(); virtual void vf1(); virtual void vf2(); };
struct B { int b; virtual void g(); };
struct X { void test( ); };
void testX() { &X::test; }
}
+
+namespace test7 {
+ struct A { void foo(); virtual void vfoo(); };
+ struct B { void foo(); virtual void vfoo(); };
+ struct C : A, B { void foo(); virtual void vfoo(); };
+
+ // CHECK-ARM: @_ZN5test74ptr0E = global {{.*}} { i32 ptrtoint ({{.*}}* @_ZN5test71A3fooEv to i32), i32 0 }
+ // CHECK-ARM: @_ZN5test74ptr1E = global {{.*}} { i32 ptrtoint ({{.*}}* @_ZN5test71B3fooEv to i32), i32 8 }
+ // CHECK-ARM: @_ZN5test74ptr2E = global {{.*}} { i32 ptrtoint ({{.*}}* @_ZN5test71C3fooEv to i32), i32 0 }
+ // CHECK-ARM: @_ZN5test74ptr3E = global {{.*}} { i32 0, i32 1 }
+ // CHECK-ARM: @_ZN5test74ptr4E = global {{.*}} { i32 0, i32 9 }
+ // CHECK-ARM: @_ZN5test74ptr5E = global {{.*}} { i32 0, i32 1 }
+ void (C::*ptr0)() = &A::foo;
+ void (C::*ptr1)() = &B::foo;
+ void (C::*ptr2)() = &C::foo;
+ void (C::*ptr3)() = &A::vfoo;
+ void (C::*ptr4)() = &B::vfoo;
+ void (C::*ptr5)() = &C::vfoo;
+}