[PATCH] [ms-cxxabi] Implement member pointer comparisons

Reid Kleckner rnk at google.com
Tue Apr 30 09:14:20 PDT 2013


Any thoughts on this?

On Fri, Apr 19, 2013 at 11:51 AM, Reid Kleckner <rnk at google.com> wrote:
> 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 at 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 at 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 at 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 at 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 at 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: }
> +}



More information about the cfe-commits mailing list