Index: lib/CodeGen/MicrosoftCXXABI.cpp =================================================================== --- lib/CodeGen/MicrosoftCXXABI.cpp +++ lib/CodeGen/MicrosoftCXXABI.cpp @@ -149,6 +149,12 @@ virtual llvm::Constant *EmitMemberDataPointer(const MemberPointerType *MPT, CharUnits offset); + virtual llvm::Value *EmitMemberPointerComparison(CodeGenFunction &CGF, + llvm::Value *L, + llvm::Value *R, + const MemberPointerType *MPT, + bool Inequality); + virtual llvm::Value *EmitMemberPointerIsNotNull(CodeGenFunction &CGF, llvm::Value *MemPtr, const MemberPointerType *MPT); @@ -415,6 +421,10 @@ return Inheritance == MSIM_Unspecified; } +static bool hasOnlyOneField(MSInheritanceModel Inheritance) { + return Inheritance <= MSIM_SinglePolymorphic; +} + // Only member pointers to functions need a this adjustment, since it can be // combined with the field offset for data pointers. static bool hasNonVirtualBaseAdjustmentField(const MemberPointerType *MPT, @@ -531,6 +541,66 @@ return llvm::ConstantStruct::getAnon(fields); } +/// Member pointers are the same if they're either bitwise identical *or* both +/// null. Null-ness for function members is determined by the first field, +/// while for data member pointers we must compare all fields. +llvm::Value * +MicrosoftCXXABI::EmitMemberPointerComparison(CodeGenFunction &CGF, + llvm::Value *L, + llvm::Value *R, + const MemberPointerType *MPT, + bool Inequality) { + CGBuilderTy &Builder = CGF.Builder; + llvm::ICmpInst::Predicate Eq; + llvm::Instruction::BinaryOps And, Or; + if (Inequality) { + Eq = llvm::ICmpInst::ICMP_NE; + And = llvm::Instruction::Or; + Or = llvm::Instruction::And; + } else { + Eq = llvm::ICmpInst::ICMP_EQ; + And = llvm::Instruction::And; + Or = llvm::Instruction::Or; + } + + // If this is a single field member pointer (single inheritance), this is a + // single icmp. + const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl(); + MSInheritanceModel Inheritance = RD->getMSInheritanceModel(); + if (hasOnlyOneField(Inheritance)) + return Builder.CreateICmp(Eq, L, R); + + // Compare the first field. + llvm::Value *L0 = Builder.CreateExtractValue(L, 0, "lhs.0"); + llvm::Value *R0 = Builder.CreateExtractValue(R, 0, "rhs.0"); + llvm::Value *Cmp0 = Builder.CreateICmp(Eq, L0, R0); + + // Compare everything other than the first field. + llvm::Value *Res = 0; + for (unsigned I = 1, E = cast(L->getType())->getNumElements(); + I != E; ++I) { + llvm::Value *LField = Builder.CreateExtractValue(L, I); + llvm::Value *RField = Builder.CreateExtractValue(R, I); + llvm::Value *Cmp = Builder.CreateICmp(Eq, LField, RField); + if (Res) + Res = Builder.CreateBinOp(And, Res, Cmp, "memptr.tobool"); + else + Res = Cmp; + } + + // Check if the first field is 0 if this is a function pointer. + if (MPT->isMemberFunctionPointer()) { + // (l1 == r1 && ...) || l0 == 0 + llvm::Value *Zero = llvm::Constant::getNullValue(L0->getType()); + llvm::Value *IsZero = Builder.CreateICmp(Eq, L0, Zero); + Res = Builder.CreateBinOp(Or, Res, IsZero, "memptr.tobool"); + } + + // Combine the comparison of the first field, which must always be true for + // this comparison to succeeed. + return Builder.CreateBinOp(And, Res, Cmp0, "memptr.tobool"); +} + llvm::Value * MicrosoftCXXABI::EmitMemberPointerIsNotNull(CodeGenFunction &CGF, llvm::Value *MemPtr, Index: test/CodeGenCXX/microsoft-abi-member-pointers.cpp =================================================================== --- test/CodeGenCXX/microsoft-abi-member-pointers.cpp +++ test/CodeGenCXX/microsoft-abi-member-pointers.cpp @@ -222,3 +222,91 @@ // CHECK: ret void // CHECK: } } + +bool compareSingleFunctionMemptr(void (Single::*l)(), void (Single::*r)()) { + return l == r; +// Should only be one comparison here. +// CHECK: define zeroext i1 @"\01?compareSingleFunctionMemptr@@YA_NP8Single@@AEXXZ0@Z"{{.*}} { +// CHECK-NOT: icmp +// CHECK: %[[r:.*]] = icmp eq +// CHECK-NOT: icmp +// CHECK: ret i1 %[[r]] +// CHECK: } +} + +bool compareNeqSingleFunctionMemptr(void (Single::*l)(), void (Single::*r)()) { + return l != r; +// Should only be one comparison here. +// CHECK: define zeroext i1 @"\01?compareNeqSingleFunctionMemptr@@YA_NP8Single@@AEXXZ0@Z"{{.*}} { +// CHECK-NOT: icmp +// CHECK: %[[r:.*]] = icmp ne +// CHECK-NOT: icmp +// CHECK: ret i1 %[[r]] +// CHECK: } +} + +bool unspecFuncMemptrEq(void (Unspecified::*l)(), void (Unspecified::*r)()) { + return l == r; +// CHECK: define zeroext i1 @"\01?unspecFuncMemptrEq@@YA_NP8Unspecified@@AEXXZ0@Z"{{.*}} { +// CHECK: %[[lhs0:.*]] = extractvalue { i8*, i32, i32, i32 } %[[l:.*]], 0 +// CHECK: %{{.*}} = extractvalue { i8*, i32, i32, i32 } %[[r:.*]], 0 +// CHECK: %[[cmp0:.*]] = icmp eq i8* %[[lhs0]], %{{.*}} +// CHECK: %{{.*}} = extractvalue { i8*, i32, i32, i32 } %[[l]], 1 +// CHECK: %{{.*}} = extractvalue { i8*, i32, i32, i32 } %[[r]], 1 +// CHECK: %[[cmp1:.*]] = icmp eq i32 +// CHECK: %{{.*}} = extractvalue { i8*, i32, i32, i32 } %[[l]], 2 +// CHECK: %{{.*}} = extractvalue { i8*, i32, i32, i32 } %[[r]], 2 +// CHECK: %[[cmp2:.*]] = icmp eq i32 +// CHECK: %[[res12:.*]] = and i1 %[[cmp1]], %[[cmp2]] +// CHECK: %{{.*}} = extractvalue { i8*, i32, i32, i32 } %[[l]], 3 +// CHECK: %{{.*}} = extractvalue { i8*, i32, i32, i32 } %[[r]], 3 +// CHECK: %[[cmp3:.*]] = icmp eq i32 +// CHECK: %[[res123:.*]] = and i1 %[[res12]], %[[cmp3]] +// CHECK: %[[iszero:.*]] = icmp eq i8* %[[lhs0]], null +// CHECK: %[[bits_or_null:.*]] = or i1 %[[res123]], %[[iszero]] +// CHECK: %{{.*}} = and i1 %[[bits_or_null]], %[[cmp0]] +// CHECK: ret i1 %{{.*}} +// CHECK: } +} + +bool unspecFuncMemptrNeq(void (Unspecified::*l)(), void (Unspecified::*r)()) { + return l != r; +// CHECK: define zeroext i1 @"\01?unspecFuncMemptrNeq@@YA_NP8Unspecified@@AEXXZ0@Z"{{.*}} { +// CHECK: %[[lhs0:.*]] = extractvalue { i8*, i32, i32, i32 } %[[l:.*]], 0 +// CHECK: %{{.*}} = extractvalue { i8*, i32, i32, i32 } %[[r:.*]], 0 +// CHECK: %[[cmp0:.*]] = icmp ne i8* %[[lhs0]], %{{.*}} +// CHECK: %{{.*}} = extractvalue { i8*, i32, i32, i32 } %[[l]], 1 +// CHECK: %{{.*}} = extractvalue { i8*, i32, i32, i32 } %[[r]], 1 +// CHECK: %[[cmp1:.*]] = icmp ne i32 +// CHECK: %{{.*}} = extractvalue { i8*, i32, i32, i32 } %[[l]], 2 +// CHECK: %{{.*}} = extractvalue { i8*, i32, i32, i32 } %[[r]], 2 +// CHECK: %[[cmp2:.*]] = icmp ne i32 +// CHECK: %[[res12:.*]] = or i1 %[[cmp1]], %[[cmp2]] +// CHECK: %{{.*}} = extractvalue { i8*, i32, i32, i32 } %[[l]], 3 +// CHECK: %{{.*}} = extractvalue { i8*, i32, i32, i32 } %[[r]], 3 +// CHECK: %[[cmp3:.*]] = icmp ne i32 +// CHECK: %[[res123:.*]] = or i1 %[[res12]], %[[cmp3]] +// CHECK: %[[iszero:.*]] = icmp ne i8* %[[lhs0]], null +// CHECK: %[[bits_or_null:.*]] = and i1 %[[res123]], %[[iszero]] +// CHECK: %{{.*}} = or i1 %[[bits_or_null]], %[[cmp0]] +// CHECK: ret i1 %{{.*}} +// CHECK: } +} + +bool unspecDataMemptrEq(int Unspecified::*l, int Unspecified::*r) { + return l == r; +// CHECK: define zeroext i1 @"\01?unspecDataMemptrEq@@YA_NPQUnspecified@@H0@Z"{{.*}} { +// CHECK: extractvalue { i32, i32, i32 } %{{.*}}, 0 +// CHECK: extractvalue { i32, i32, i32 } %{{.*}}, 0 +// CHECK: icmp eq i32 +// CHECK: extractvalue { i32, i32, i32 } %{{.*}}, 1 +// CHECK: extractvalue { i32, i32, i32 } %{{.*}}, 1 +// CHECK: icmp eq i32 +// CHECK: extractvalue { i32, i32, i32 } %{{.*}}, 2 +// CHECK: extractvalue { i32, i32, i32 } %{{.*}}, 2 +// CHECK: icmp eq i32 +// CHECK: and i1 +// CHECK: and i1 +// CHECK: ret i1 +// CHECK: } +}