void LLVMContext::CopyDataImpl()

in libraries/value/src/LLVMContext.cpp [1042:1195]


    void LLVMContext::CopyDataImpl(const Value& source, Value& destination)
    {
        if (destination.IsConstant())
        {
            if (source.IsConstant())
            {
                return _computeContext.CopyData(source, destination);
            }
            else
            {
                auto emittableDestination = EnsureEmittable(destination);
                CopyDataImpl(source, emittableDestination);
                destination.SetData(emittableDestination);
            }
        }
        else
        {
            if (!TypeCompatible(destination, source))
            {
                throw InputException(InputExceptionErrors::typeMismatch);
            }

            enum class CopyType
            {
                DirectScalarPassThrough,
                DirectScalarCopy,
                Memory,
                Reference
            };
            CopyType copyType{};

            if (auto srcPtrLevel = source.PointerLevel(); srcPtrLevel < 0)
            {
                throw LogicException(LogicExceptionErrors::illegalState);
            }
            else if (srcPtrLevel == 0)
            {
                switch (destination.PointerLevel())
                {
                case 0:
                    copyType = CopyType::DirectScalarPassThrough;
                    break;
                case 1:
                    copyType = CopyType::DirectScalarCopy;
                    break;
                default:
                    throw LogicException(LogicExceptionErrors::illegalState);
                }
                if (source.GetLayout() != ScalarLayout || destination.GetLayout() != ScalarLayout)
                {
                    throw InputException(InputExceptionErrors::invalidSize);
                }
            }
            else if (srcPtrLevel == 1)
            {
                if (destination.PointerLevel() != 1)
                {
                    throw LogicException(LogicExceptionErrors::illegalState);
                }
                else
                {
                    if (destination.GetLayout() != source.GetLayout())
                    {
                        throw InputException(InputExceptionErrors::sizeMismatch);
                    }
                    copyType = CopyType::Memory;
                }
            }
            else if (destination.PointerLevel() == srcPtrLevel)
            {
                assert(srcPtrLevel > 1);
                if (source.IsConstant())
                {
                    throw LogicException(LogicExceptionErrors::illegalState);
                }
                copyType = CopyType::Reference;
            }
            else
            {
                throw LogicException(LogicExceptionErrors::illegalState);
            }

            auto& irEmitter = _emitter.GetIREmitter();
            auto destValue = ToLLVMValue(destination);

            if (source.IsConstant())
            {
                // we're only copying active areas below. should we copy padded too?
                auto& layout = source.GetLayout();
                std::visit(
                    VariantVisitor{ [](Emittable) {},
                                    [destValue, &irEmitter, &layout](auto&& data) {
                                        ConstantForLoop(layout, [&](int offset) {
                                            auto srcAtOffset = irEmitter.Literal(*(data + offset));
                                            auto destOffset = irEmitter.Literal(offset);
                                            auto destAtOffset = irEmitter.PointerOffset(destValue, destOffset);
                                            (void)irEmitter.Store(destAtOffset, srcAtOffset);
                                        });
                                    } },
                    source.GetUnderlyingData());
            }
            else
            {
                auto srcValue = ToLLVMValue(source);
                if (srcValue == destValue)
                {
                    return;
                }
                switch (copyType)
                {
                case CopyType::DirectScalarPassThrough:
                    destination.SetData(Emittable{ srcValue });
                    break;
                case CopyType::DirectScalarCopy:
                {
                    auto destAtOffset = irEmitter.PointerOffset(destValue, irEmitter.Zero(VariableType::Int32));
                    irEmitter.Store(destAtOffset, srcValue);
                    break;
                }
                case CopyType::Memory:
                    if (auto& layout = source.GetLayout(); layout.IsContiguous())
                    {
                        assert(copyType == CopyType::Memory);
                        auto llvmType = srcValue->getType()->getContainedType(0);
                        auto primSize = irEmitter.SizeOf(llvmType);
                        auto memorySize = irEmitter.Literal(static_cast<int64_t>(layout.GetMemorySize() * primSize));
                        irEmitter.MemoryCopy(srcValue,
                                             destValue,
                                             memorySize);
                    }
                    else
                    {
                        ForImpl(
                            layout, [&](std::vector<Scalar> index) {
                                auto offsetSource = source.Offset(detail::CalculateOffset(source.GetLayout(), index));
                                auto offsetDest = destination.Offset(detail::CalculateOffset(destination.GetLayout(), index));
                                (void)irEmitter.Store(ToLLVMValue(offsetDest), irEmitter.Load(ToLLVMValue(offsetSource)));
                            },
                            "");
                    }
                    break;
                case CopyType::Reference:
                {
                    auto srcAtOffset = irEmitter.Load(srcValue);
                    irEmitter.Store(destValue, srcAtOffset);
                    destination.SetLayout(source.GetLayout());
                    break;
                }
                default:
                    throw LogicException(LogicExceptionErrors::illegalState);
                }
            }
        }
    }