Skip to content

Commit b30c166

Browse files
author
Erich Keane
committed
Implement constexpr BinaryOperator for vector types
These operations do member-wise versions of the all of the listed operations. This patch implements all of the binaryoperators for these types. Note that the test is required to use codegen as I could not come up with a good way to validate the values without the array-subscript operator implemented (which is likely a much more involved change). Differential Reivision: https://reviews.llvm.org/D79755
1 parent 98c2f4e commit b30c166

File tree

2 files changed

+817
-4
lines changed

2 files changed

+817
-4
lines changed

clang/lib/AST/ExprConstant.cpp

Lines changed: 201 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2664,6 +2664,155 @@ static bool handleFloatFloatBinOp(EvalInfo &Info, const Expr *E,
26642664
return true;
26652665
}
26662666

2667+
static bool handleLogicalOpForVector(const APInt &LHSValue,
2668+
BinaryOperatorKind Opcode,
2669+
const APInt &RHSValue, APInt &Result) {
2670+
bool LHS = (LHSValue != 0);
2671+
bool RHS = (RHSValue != 0);
2672+
2673+
if (Opcode == BO_LAnd)
2674+
Result = LHS && RHS;
2675+
else
2676+
Result = LHS || RHS;
2677+
return true;
2678+
}
2679+
static bool handleLogicalOpForVector(const APFloat &LHSValue,
2680+
BinaryOperatorKind Opcode,
2681+
const APFloat &RHSValue, APInt &Result) {
2682+
bool LHS = !LHSValue.isZero();
2683+
bool RHS = !RHSValue.isZero();
2684+
2685+
if (Opcode == BO_LAnd)
2686+
Result = LHS && RHS;
2687+
else
2688+
Result = LHS || RHS;
2689+
return true;
2690+
}
2691+
2692+
static bool handleLogicalOpForVector(const APValue &LHSValue,
2693+
BinaryOperatorKind Opcode,
2694+
const APValue &RHSValue, APInt &Result) {
2695+
// The result is always an int type, however operands match the first.
2696+
if (LHSValue.getKind() == APValue::Int)
2697+
return handleLogicalOpForVector(LHSValue.getInt(), Opcode,
2698+
RHSValue.getInt(), Result);
2699+
assert(LHSValue.getKind() == APValue::Float && "Should be no other options");
2700+
return handleLogicalOpForVector(LHSValue.getFloat(), Opcode,
2701+
RHSValue.getFloat(), Result);
2702+
}
2703+
2704+
template <typename APTy>
2705+
static bool
2706+
handleCompareOpForVectorHelper(const APTy &LHSValue, BinaryOperatorKind Opcode,
2707+
const APTy &RHSValue, APInt &Result) {
2708+
switch (Opcode) {
2709+
default:
2710+
llvm_unreachable("unsupported binary operator");
2711+
case BO_EQ:
2712+
Result = (LHSValue == RHSValue);
2713+
break;
2714+
case BO_NE:
2715+
Result = (LHSValue != RHSValue);
2716+
break;
2717+
case BO_LT:
2718+
Result = (LHSValue < RHSValue);
2719+
break;
2720+
case BO_GT:
2721+
Result = (LHSValue > RHSValue);
2722+
break;
2723+
case BO_LE:
2724+
Result = (LHSValue <= RHSValue);
2725+
break;
2726+
case BO_GE:
2727+
Result = (LHSValue >= RHSValue);
2728+
break;
2729+
}
2730+
2731+
return true;
2732+
}
2733+
2734+
static bool handleCompareOpForVector(const APValue &LHSValue,
2735+
BinaryOperatorKind Opcode,
2736+
const APValue &RHSValue, APInt &Result) {
2737+
// The result is always an int type, however operands match the first.
2738+
if (LHSValue.getKind() == APValue::Int)
2739+
return handleCompareOpForVectorHelper(LHSValue.getInt(), Opcode,
2740+
RHSValue.getInt(), Result);
2741+
assert(LHSValue.getKind() == APValue::Float && "Should be no other options");
2742+
return handleCompareOpForVectorHelper(LHSValue.getFloat(), Opcode,
2743+
RHSValue.getFloat(), Result);
2744+
}
2745+
2746+
// Perform binary operations for vector types, in place on the LHS.
2747+
static bool handleVectorVectorBinOp(EvalInfo &Info, const Expr *E,
2748+
BinaryOperatorKind Opcode,
2749+
APValue &LHSValue,
2750+
const APValue &RHSValue) {
2751+
assert(Opcode != BO_PtrMemD && Opcode != BO_PtrMemI &&
2752+
"Operation not supported on vector types");
2753+
2754+
const auto *VT = E->getType()->castAs<VectorType>();
2755+
unsigned NumElements = VT->getNumElements();
2756+
QualType EltTy = VT->getElementType();
2757+
2758+
// In the cases (typically C as I've observed) where we aren't evaluating
2759+
// constexpr but are checking for cases where the LHS isn't yet evaluatable,
2760+
// just give up.
2761+
if (!LHSValue.isVector()) {
2762+
assert(LHSValue.isLValue() &&
2763+
"A vector result that isn't a vector OR uncalculated LValue");
2764+
Info.FFDiag(E);
2765+
return false;
2766+
}
2767+
2768+
assert(LHSValue.getVectorLength() == NumElements &&
2769+
RHSValue.getVectorLength() == NumElements && "Different vector sizes");
2770+
2771+
SmallVector<APValue, 4> ResultElements;
2772+
2773+
for (unsigned EltNum = 0; EltNum < NumElements; ++EltNum) {
2774+
APValue LHSElt = LHSValue.getVectorElt(EltNum);
2775+
APValue RHSElt = RHSValue.getVectorElt(EltNum);
2776+
2777+
if (EltTy->isIntegerType()) {
2778+
APSInt EltResult{Info.Ctx.getIntWidth(EltTy),
2779+
EltTy->isUnsignedIntegerType()};
2780+
bool Success = true;
2781+
2782+
if (BinaryOperator::isLogicalOp(Opcode))
2783+
Success = handleLogicalOpForVector(LHSElt, Opcode, RHSElt, EltResult);
2784+
else if (BinaryOperator::isComparisonOp(Opcode))
2785+
Success = handleCompareOpForVector(LHSElt, Opcode, RHSElt, EltResult);
2786+
else
2787+
Success = handleIntIntBinOp(Info, E, LHSElt.getInt(), Opcode,
2788+
RHSElt.getInt(), EltResult);
2789+
2790+
if (!Success) {
2791+
Info.FFDiag(E);
2792+
return false;
2793+
}
2794+
ResultElements.emplace_back(EltResult);
2795+
2796+
} else if (EltTy->isFloatingType()) {
2797+
assert(LHSElt.getKind() == APValue::Float &&
2798+
RHSElt.getKind() == APValue::Float &&
2799+
"Mismatched LHS/RHS/Result Type");
2800+
APFloat LHSFloat = LHSElt.getFloat();
2801+
2802+
if (!handleFloatFloatBinOp(Info, E, LHSFloat, Opcode,
2803+
RHSElt.getFloat())) {
2804+
Info.FFDiag(E);
2805+
return false;
2806+
}
2807+
2808+
ResultElements.emplace_back(LHSFloat);
2809+
}
2810+
}
2811+
2812+
LHSValue = APValue(ResultElements.data(), ResultElements.size());
2813+
return true;
2814+
}
2815+
26672816
/// Cast an lvalue referring to a base subobject to a derived class, by
26682817
/// truncating the lvalue's path to the given length.
26692818
static bool CastToDerivedClass(EvalInfo &Info, const Expr *E, LValue &Result,
@@ -3910,12 +4059,26 @@ struct CompoundAssignSubobjectHandler {
39104059
return false;
39114060
case APValue::LValue:
39124061
return foundPointer(Subobj, SubobjType);
4062+
case APValue::Vector:
4063+
return foundVector(Subobj, SubobjType);
39134064
default:
39144065
// FIXME: can this happen?
39154066
Info.FFDiag(E);
39164067
return false;
39174068
}
39184069
}
4070+
4071+
bool foundVector(APValue &Value, QualType SubobjType) {
4072+
if (!checkConst(SubobjType))
4073+
return false;
4074+
4075+
if (!SubobjType->isVectorType()) {
4076+
Info.FFDiag(E);
4077+
return false;
4078+
}
4079+
return handleVectorVectorBinOp(Info, E, Opcode, Value, RHS);
4080+
}
4081+
39194082
bool found(APSInt &Value, QualType SubobjType) {
39204083
if (!checkConst(SubobjType))
39214084
return false;
@@ -9516,10 +9679,9 @@ namespace {
95169679
bool VisitCastExpr(const CastExpr* E);
95179680
bool VisitInitListExpr(const InitListExpr *E);
95189681
bool VisitUnaryImag(const UnaryOperator *E);
9519-
// FIXME: Missing: unary -, unary ~, binary add/sub/mul/div,
9520-
// binary comparisons, binary and/or/xor,
9521-
// conditional operator (for GNU conditional select),
9522-
// shufflevector, ExtVectorElementExpr
9682+
bool VisitBinaryOperator(const BinaryOperator *E);
9683+
// FIXME: Missing: unary -, unary ~, conditional operator (for GNU
9684+
// conditional select), shufflevector, ExtVectorElementExpr
95239685
};
95249686
} // end anonymous namespace
95259687

@@ -9667,6 +9829,41 @@ bool VectorExprEvaluator::VisitUnaryImag(const UnaryOperator *E) {
96679829
return ZeroInitialization(E);
96689830
}
96699831

9832+
bool VectorExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
9833+
BinaryOperatorKind Op = E->getOpcode();
9834+
assert(Op != BO_PtrMemD && Op != BO_PtrMemI && Op != BO_Cmp &&
9835+
"Operation not supported on vector types");
9836+
9837+
if (Op == BO_Comma)
9838+
return ExprEvaluatorBaseTy::VisitBinaryOperator(E);
9839+
9840+
Expr *LHS = E->getLHS();
9841+
Expr *RHS = E->getRHS();
9842+
9843+
assert(LHS->getType()->isVectorType() && RHS->getType()->isVectorType() &&
9844+
"Must both be vector types");
9845+
// Checking JUST the types are the same would be fine, except shifts don't
9846+
// need to have their types be the same (since you always shift by an int).
9847+
assert(LHS->getType()->getAs<VectorType>()->getNumElements() ==
9848+
E->getType()->getAs<VectorType>()->getNumElements() &&
9849+
RHS->getType()->getAs<VectorType>()->getNumElements() ==
9850+
E->getType()->getAs<VectorType>()->getNumElements() &&
9851+
"All operands must be the same size.");
9852+
9853+
APValue LHSValue;
9854+
APValue RHSValue;
9855+
bool LHSOK = Evaluate(LHSValue, Info, LHS);
9856+
if (!LHSOK && !Info.noteFailure())
9857+
return false;
9858+
if (!Evaluate(RHSValue, Info, RHS) || !LHSOK)
9859+
return false;
9860+
9861+
if (!handleVectorVectorBinOp(Info, E, Op, LHSValue, RHSValue))
9862+
return false;
9863+
9864+
return Success(LHSValue, E);
9865+
}
9866+
96709867
//===----------------------------------------------------------------------===//
96719868
// Array Evaluation
96729869
//===----------------------------------------------------------------------===//

0 commit comments

Comments
 (0)