Hi rjmccall,

Like Itanium, comparisons are basically bitwise comparisons of the two
values, with an exception for null member function pointers.  If two
function pointers are null, only the function pointer field matters for
comparison purposes.  The rest of the bits can be arbitrary.  We take
advantage of this in isZeroInitializable(), and it may matter once we
start emitting conversions.

http://llvm-reviews.chandlerc.com/D695

Files:
  lib/CodeGen/MicrosoftCXXABI.cpp
  test/CodeGenCXX/microsoft-abi-member-pointers.cpp

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<llvm::StructType>(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: }
+}
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<llvm::StructType>(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: }
+}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to