Value LLVMContext::LogicalOperationImpl()

in libraries/value/src/LLVMContext.cpp [1421:1550]


    Value LLVMContext::LogicalOperationImpl(ValueLogicalOperation op, Value source1, Value source2)
    {
        if (source1.GetLayout() != source2.GetLayout())
        {
            throw InputException(InputExceptionErrors::sizeMismatch);
        }

        if (source1.IsConstant() && source2.IsConstant())
        {
            return _computeContext.LogicalOperation(op, source1, source2);
        }

        auto comparisonOp = TypedComparison::none;
        bool isFp = source1.IsFloatingPoint();
        switch (op)
        {
        case ValueLogicalOperation::equality:
            comparisonOp = isFp ? TypedComparison::equalsFloat : TypedComparison::equals;
            break;
        case ValueLogicalOperation::inequality:
            comparisonOp = isFp ? TypedComparison::notEqualsFloat : TypedComparison::notEquals;
            break;
        case ValueLogicalOperation::greaterthan:
            comparisonOp = isFp ? TypedComparison::greaterThanFloat : TypedComparison::greaterThan;
            break;
        case ValueLogicalOperation::greaterthanorequal:
            comparisonOp = isFp ? TypedComparison::greaterThanOrEqualsFloat : TypedComparison::greaterThanOrEquals;
            break;
        case ValueLogicalOperation::lessthan:
            comparisonOp = isFp ? TypedComparison::lessThanFloat : TypedComparison::lessThan;
            break;
        case ValueLogicalOperation::lessthanorequal:
            comparisonOp = isFp ? TypedComparison::lessThanOrEqualsFloat : TypedComparison::lessThanOrEquals;
            break;
        }

        Value returnValue = std::visit(
            VariantVisitor{
                [this,
                 comparisonOp,
                 &source1,
                 &source2](Emittable source1Data) -> Value {
                    // source1 is an Emittable type, so source2 can be constant or Emittable
                    return std::visit(
                        VariantVisitor{
                            [&, this](Emittable source2Data) -> Value {
                                auto& fn = this->GetFunctionEmitter();
                                auto result = fn.TrueBit();

                                ForImpl(
                                    source1.GetLayout(),
                                    [&](std::vector<Scalar> index) {
                                        auto offsetSource1 = source1.Offset(detail::CalculateOffset(source1.GetLayout(), index));
                                        auto offsetSource2 = source2.Offset(detail::CalculateOffset(source2.GetLayout(), index));
                                        result = fn.LogicalAnd(
                                            result,
                                            fn.Comparison(
                                                comparisonOp,
                                                fn.Load(ToLLVMValue(offsetSource1)),
                                                fn.Load(ToLLVMValue(offsetSource2))));
                                    },
                                    "");

                                return { Emittable{ result }, ScalarLayout };
                            },
                            [&, this](auto&& source2Data) -> Value {
                                using Type = std::remove_pointer_t<std::decay_t<decltype(source2Data)>>;
                                using CastType = std::conditional_t<std::is_same_v<Type, Boolean>, bool, Type>;
                                auto& fn = this->GetFunctionEmitter();

                                LLVMValue result = nullptr;
                                auto llvmOp1 = source1Data.GetDataAs<LLVMValue>();
                                if (source1.PointerLevel() == 0)
                                {
                                    result = fn.Comparison(
                                        comparisonOp,
                                        llvmOp1,
                                        fn.Literal(static_cast<CastType>(source2Data[0])));
                                }
                                else
                                {
                                    result = fn.TrueBit();
                                    ConstantForLoop(source1.GetLayout(), [&](const MemoryCoordinates& logicalCoordinates) {
                                        auto source1Offset = source1.GetLayout().GetLogicalEntryOffset(logicalCoordinates);
                                        auto source2Offset = source2.GetLayout().GetLogicalEntryOffset(logicalCoordinates);

                                        result = fn.LogicalAnd(
                                            result,
                                            fn.Comparison(
                                                comparisonOp,
                                                fn.ValueAt(llvmOp1, source1Offset),
                                                fn.Literal(static_cast<CastType>(source2Data[source2Offset]))));
                                    });
                                }

                                return { Emittable{ result }, ScalarLayout };
                            } },
                        source2.GetUnderlyingData());
                },
                [this,
                 comparisonOp,
                 &source2Data = source2.GetUnderlyingData(),
                 &source1Layout = source1.GetLayout(),
                 &source2Layout = source2.GetLayout()](auto&& source1Data) -> Value {
                    // source1 is constant, so source2 has to be an Emittable type
                    using Type = std::remove_pointer_t<std::decay_t<decltype(source1Data)>>;
                    using CastType = std::conditional_t<std::is_same_v<Type, Boolean>, bool, Type>;

                    auto& fn = GetFunctionEmitter();
                    auto result = fn.TrueBit();
                    auto llvmOp2 = std::get<Emittable>(source2Data).GetDataAs<LLVMValue>();

                    ConstantForLoop(source1Layout, [&](const MemoryCoordinates& logicalCoordinates) {
                        auto source1Offset = source1Layout.GetLogicalEntryOffset(logicalCoordinates);
                        auto source2Offset = source2Layout.GetLogicalEntryOffset(logicalCoordinates);

                        result = fn.LogicalAnd(
                            result,
                            fn.Comparison(
                                comparisonOp,
                                fn.Literal(static_cast<CastType>(source1Data[source1Offset])),
                                fn.ValueAt(llvmOp2, source2Offset)));
                    });

                    return { Emittable{ result }, ScalarLayout };
                } },
            source1.GetUnderlyingData());

        return returnValue;
    }