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);
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,
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;
+
+ // Handle != comparisons by switching the sense of all boolean operations.
+ 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, "memptr.cmp.first");
+
+ // Compare everything other than the first field.
+ llvm::Value *Res = 0;
+ llvm::StructType *LType = cast<llvm::StructType>(L->getType());
+ for (unsigned I = 1, E = LType->getNumElements(); I != E; ++I) {
+ llvm::Value *LF = Builder.CreateExtractValue(L, I);
+ llvm::Value *RF = Builder.CreateExtractValue(R, I);
+ llvm::Value *Cmp = Builder.CreateICmp(Eq, LF, RF, "memptr.cmp.rest");
+ if (Res)
+ Res = Builder.CreateBinOp(And, Res, Cmp);
+ 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, "memptr.cmp.iszero");
+ Res = Builder.CreateBinOp(Or, Res, IsZero);
+ }
+
+ // Combine the comparison of the first field, which must always be true for
+ // this comparison to succeeed.
+ return Builder.CreateBinOp(And, Res, Cmp0, "memptr.cmp");
+}
+
llvm::Value *
MicrosoftCXXABI::EmitMemberPointerIsNotNull(CodeGenFunction &CGF,
llvm::Value *MemPtr,
// 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: }
+}