summaryrefslogtreecommitdiffstats
path: root/clang/lib/CodeGen/CGExprAgg.cpp
diff options
context:
space:
mode:
authorEric Fiselier <eric@efcs.ca>2018-05-07 21:07:10 +0000
committerEric Fiselier <eric@efcs.ca>2018-05-07 21:07:10 +0000
commit0683c0e68d31d18f6e4fedb270317844a4912882 (patch)
tree1e6f3b6ff82d931d904dd7f6e54648849d965b99 /clang/lib/CodeGen/CGExprAgg.cpp
parentf53d9abd7e1b5581d83ae1572829535ff1d6e183 (diff)
downloadbcm5719-llvm-0683c0e68d31d18f6e4fedb270317844a4912882.tar.gz
bcm5719-llvm-0683c0e68d31d18f6e4fedb270317844a4912882.zip
[C++2a] Implement operator<=> CodeGen and ExprConstant
Summary: This patch tackles long hanging fruit for the builtin operator<=> expressions. It is currently needs some cleanup before landing, but I want to get some initial feedback. The main changes are: * Lookup, build, and store the required standard library types and expressions in `ASTContext`. By storing them in ASTContext we don't need to store (and duplicate) the required expressions in the BinaryOperator AST nodes. * Implement [expr.spaceship] checking, including diagnosing narrowing conversions. * Implement `ExprConstant` for builtin spaceship operators. * Implement builitin operator<=> support in `CodeGenAgg`. Initially I emitted the required comparisons using `ScalarExprEmitter::VisitBinaryOperator`, but this caused the operand expressions to be emitted once for every required cmp. * Implement [builtin.over] with modifications to support the intent of P0946R0. See the note on `BuiltinOperatorOverloadBuilder::addThreeWayArithmeticOverloads` for more information about the workaround. Reviewers: rsmith, aaron.ballman, majnemer, rnk, compnerd, rjmccall Reviewed By: rjmccall Subscribers: rjmccall, rsmith, aaron.ballman, junbuml, mgorny, cfe-commits Differential Revision: https://reviews.llvm.org/D45476 llvm-svn: 331677
Diffstat (limited to 'clang/lib/CodeGen/CGExprAgg.cpp')
-rw-r--r--clang/lib/CodeGen/CGExprAgg.cpp145
1 files changed, 145 insertions, 0 deletions
diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp
index 6693ddd7478..23d74dae4e3 100644
--- a/clang/lib/CodeGen/CGExprAgg.cpp
+++ b/clang/lib/CodeGen/CGExprAgg.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "CodeGenFunction.h"
+#include "CGCXXABI.h"
#include "CGObjCRuntime.h"
#include "CodeGenModule.h"
#include "ConstantEmitter.h"
@@ -145,6 +146,7 @@ public:
void VisitPointerToDataMemberBinaryOperator(const BinaryOperator *BO);
void VisitBinAssign(const BinaryOperator *E);
void VisitBinComma(const BinaryOperator *E);
+ void VisitBinCmp(const BinaryOperator *E);
void VisitObjCMessageExpr(ObjCMessageExpr *E);
void VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) {
@@ -879,6 +881,149 @@ void AggExprEmitter::VisitStmtExpr(const StmtExpr *E) {
CGF.EmitCompoundStmt(*E->getSubStmt(), true, Dest);
}
+enum CompareKind {
+ CK_Less,
+ CK_Greater,
+ CK_Equal,
+};
+
+static llvm::Value *EmitCompare(CGBuilderTy &Builder, CodeGenFunction &CGF,
+ const BinaryOperator *E, llvm::Value *LHS,
+ llvm::Value *RHS, CompareKind Kind,
+ const char *NameSuffix = "") {
+ QualType ArgTy = E->getLHS()->getType();
+ if (const ComplexType *CT = ArgTy->getAs<ComplexType>())
+ ArgTy = CT->getElementType();
+
+ if (const auto *MPT = ArgTy->getAs<MemberPointerType>()) {
+ assert(Kind == CK_Equal &&
+ "member pointers may only be compared for equality");
+ return CGF.CGM.getCXXABI().EmitMemberPointerComparison(
+ CGF, LHS, RHS, MPT, /*IsInequality*/ false);
+ }
+
+ // Compute the comparison instructions for the specified comparison kind.
+ struct CmpInstInfo {
+ const char *Name;
+ llvm::CmpInst::Predicate FCmp;
+ llvm::CmpInst::Predicate SCmp;
+ llvm::CmpInst::Predicate UCmp;
+ };
+ CmpInstInfo InstInfo = [&]() -> CmpInstInfo {
+ using FI = llvm::FCmpInst;
+ using II = llvm::ICmpInst;
+ switch (Kind) {
+ case CK_Less:
+ return {"cmp.lt", FI::FCMP_OLT, II::ICMP_SLT, II::ICMP_ULT};
+ case CK_Greater:
+ return {"cmp.gt", FI::FCMP_OGT, II::ICMP_SGT, II::ICMP_UGT};
+ case CK_Equal:
+ return {"cmp.eq", FI::FCMP_OEQ, II::ICMP_EQ, II::ICMP_EQ};
+ }
+ }();
+
+ if (ArgTy->hasFloatingRepresentation())
+ return Builder.CreateFCmp(InstInfo.FCmp, LHS, RHS,
+ llvm::Twine(InstInfo.Name) + NameSuffix);
+ if (ArgTy->isIntegralOrEnumerationType() || ArgTy->isPointerType()) {
+ auto Inst =
+ ArgTy->hasSignedIntegerRepresentation() ? InstInfo.SCmp : InstInfo.UCmp;
+ return Builder.CreateICmp(Inst, LHS, RHS,
+ llvm::Twine(InstInfo.Name) + NameSuffix);
+ }
+
+ llvm_unreachable("unsupported aggregate binary expression should have "
+ "already been handled");
+}
+
+void AggExprEmitter::VisitBinCmp(const BinaryOperator *E) {
+ using llvm::BasicBlock;
+ using llvm::PHINode;
+ using llvm::Value;
+ assert(CGF.getContext().hasSameType(E->getLHS()->getType(),
+ E->getRHS()->getType()));
+ const ComparisonCategoryInfo &CmpInfo =
+ CGF.getContext().CompCategories.getInfoForType(E->getType());
+ assert(CmpInfo.Record->isTriviallyCopyable() &&
+ "cannot copy non-trivially copyable aggregate");
+
+ QualType ArgTy = E->getLHS()->getType();
+
+ // TODO: Handle comparing these types.
+ if (ArgTy->isVectorType())
+ return CGF.ErrorUnsupported(
+ E, "aggregate three-way comparison with vector arguments");
+ if (!ArgTy->isIntegralOrEnumerationType() && !ArgTy->isRealFloatingType() &&
+ !ArgTy->isNullPtrType() && !ArgTy->isPointerType() &&
+ !ArgTy->isMemberPointerType() && !ArgTy->isAnyComplexType()) {
+ return CGF.ErrorUnsupported(E, "aggregate three-way comparisoaoeun");
+ }
+ bool IsComplex = ArgTy->isAnyComplexType();
+
+ // Evaluate the operands to the expression and extract their values.
+ auto EmitOperand = [&](Expr *E) -> std::pair<Value *, Value *> {
+ RValue RV = CGF.EmitAnyExpr(E);
+ if (RV.isScalar())
+ return {RV.getScalarVal(), nullptr};
+ if (RV.isAggregate())
+ return {RV.getAggregatePointer(), nullptr};
+ assert(RV.isComplex());
+ return RV.getComplexVal();
+ };
+ auto LHSValues = EmitOperand(E->getLHS()),
+ RHSValues = EmitOperand(E->getRHS());
+
+ auto EmitCmp = [&](CompareKind K) {
+ Value *Cmp = EmitCompare(Builder, CGF, E, LHSValues.first, RHSValues.first,
+ K, IsComplex ? ".r" : "");
+ if (!IsComplex)
+ return Cmp;
+ assert(K == CompareKind::CK_Equal);
+ Value *CmpImag = EmitCompare(Builder, CGF, E, LHSValues.second,
+ RHSValues.second, K, ".i");
+ return Builder.CreateAnd(Cmp, CmpImag, "and.eq");
+ };
+ auto EmitCmpRes = [&](const ComparisonCategoryInfo::ValueInfo *VInfo) {
+ return Builder.getInt(VInfo->getIntValue());
+ };
+
+ Value *Select;
+ if (ArgTy->isNullPtrType()) {
+ Select = EmitCmpRes(CmpInfo.getEqualOrEquiv());
+ } else if (CmpInfo.isEquality()) {
+ Select = Builder.CreateSelect(
+ EmitCmp(CK_Equal), EmitCmpRes(CmpInfo.getEqualOrEquiv()),
+ EmitCmpRes(CmpInfo.getNonequalOrNonequiv()), "sel.eq");
+ } else if (!CmpInfo.isPartial()) {
+ Value *SelectOne =
+ Builder.CreateSelect(EmitCmp(CK_Less), EmitCmpRes(CmpInfo.getLess()),
+ EmitCmpRes(CmpInfo.getGreater()), "sel.lt");
+ Select = Builder.CreateSelect(EmitCmp(CK_Equal),
+ EmitCmpRes(CmpInfo.getEqualOrEquiv()),
+ SelectOne, "sel.eq");
+ } else {
+ Value *SelectEq = Builder.CreateSelect(
+ EmitCmp(CK_Equal), EmitCmpRes(CmpInfo.getEqualOrEquiv()),
+ EmitCmpRes(CmpInfo.getUnordered()), "sel.eq");
+ Value *SelectGT = Builder.CreateSelect(EmitCmp(CK_Greater),
+ EmitCmpRes(CmpInfo.getGreater()),
+ SelectEq, "sel.gt");
+ Select = Builder.CreateSelect(
+ EmitCmp(CK_Less), EmitCmpRes(CmpInfo.getLess()), SelectGT, "sel.lt");
+ }
+ // Create the return value in the destination slot.
+ EnsureDest(E->getType());
+ LValue DestLV = CGF.MakeAddrLValue(Dest.getAddress(), E->getType());
+
+ // Emit the address of the first (and only) field in the comparison category
+ // type, and initialize it from the constant integer value selected above.
+ LValue FieldLV = CGF.EmitLValueForFieldInitialization(
+ DestLV, *CmpInfo.Record->field_begin());
+ CGF.EmitStoreThroughLValue(RValue::get(Select), FieldLV, /*IsInit*/ true);
+
+ // All done! The result is in the Dest slot.
+}
+
void AggExprEmitter::VisitBinaryOperator(const BinaryOperator *E) {
if (E->getOpcode() == BO_PtrMemD || E->getOpcode() == BO_PtrMemI)
VisitPointerToDataMemberBinaryOperator(E);
OpenPOWER on IntegriCloud