Files
RedBear-OS/local/recipes/dev/spirv-llvm-translator/source/lib/SPIRV/SPIRVLowerMemmove.cpp
T

162 lines
5.9 KiB
C++

//===- SPIRVLowerMemmove.cpp - Lower llvm.memmove to llvm.memcpys ---------===//
//
// The LLVM/SPIRV Translator
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
// Copyright (c) 2014 Advanced Micro Devices, Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal with the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
// Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimers in the documentation
// and/or other materials provided with the distribution.
// Neither the names of Advanced Micro Devices, Inc., nor the names of its
// contributors may be used to endorse or promote products derived from this
// Software without specific prior written permission.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
// THE SOFTWARE.
//
//===----------------------------------------------------------------------===//
//
// This file implements lowering llvm.memmove into several llvm.memcpys.
//
//===----------------------------------------------------------------------===//
#include "SPIRVLowerMemmove.h"
#include "SPIRVInternal.h"
#include "libSPIRV/SPIRVDebug.h"
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/Transforms/Utils/LowerMemIntrinsics.h"
#define DEBUG_TYPE "spvmemmove"
using namespace llvm;
using namespace SPIRV;
namespace SPIRV {
void SPIRVLowerMemmoveBase::LowerMemMoveInst(MemMoveInst &I) {
// There is no direct equivalent of @llvm.memmove in SPIR-V and the closest
// instructions are 'OpCopyMemory' and 'OpCopyMemorySized'.
//
// 'OpCopyMemory' does not accept amount of bytes to copy and infers that
// from type which is being copied; also it only allows to copy value of a
// particular type to pointer pointing to the same type.
//
// 'OpCopyMemorySized' is closer to @llvm.memmove, because it actually
// copies bytes, but unlike memove it is not explicitly specified whether it
// supports overlapping source and destination. Therefore, we replace
// memmove with two 'OpCopyMemorySized' instructions: the first one copies
// bytes from source to a temporary location, the second one copies bytes
// from that temporary location to the destination.
IRBuilder<> Builder(I.getParent());
Builder.SetInsertPoint(&I);
auto *Length = cast<ConstantInt>(I.getLength());
auto *AllocaTy =
ArrayType::get(IntegerType::getInt8Ty(*Context), Length->getZExtValue());
MaybeAlign SrcAlign = I.getSourceAlign();
AllocaInst *Alloca;
{
IRBuilderBase::InsertPointGuard IG(Builder);
Builder.SetInsertPointPastAllocas(I.getParent()->getParent());
Alloca = Builder.CreateAlloca(AllocaTy);
if (SrcAlign.has_value())
Alloca->setAlignment(SrcAlign.value());
}
// FIXME: Do we need to pass the size of alloca here? From LangRef:
// > The first argument is a constant integer representing the size of the
// > object, or -1 if it is variable sized.
//
// https://llvm.org/docs/LangRef.html#llvm-lifetime-start-intrinsic
Builder.CreateLifetimeStart(Alloca);
Builder.CreateMemCpy(Alloca, SrcAlign, I.getRawSource(), SrcAlign, Length,
I.isVolatile());
auto *SecondCpy =
Builder.CreateMemCpy(I.getRawDest(), I.getDestAlign(), Alloca, SrcAlign,
Length, I.isVolatile());
Builder.CreateLifetimeEnd(Alloca);
SecondCpy->takeName(&I);
I.replaceAllUsesWith(SecondCpy);
I.dropAllReferences();
I.eraseFromParent();
}
bool SPIRVLowerMemmoveBase::expandMemMoveIntrinsicUses(Function &F) {
bool Changed = false;
for (User *U : make_early_inc_range(F.users())) {
MemMoveInst *Inst = cast<MemMoveInst>(U);
if (!isa<ConstantInt>(Inst->getLength())) {
expandMemMoveAsLoop(Inst,
TargetTransformInfo(F.getParent()->getDataLayout()));
Inst->eraseFromParent();
} else {
LowerMemMoveInst(*Inst);
}
Changed = true;
}
return Changed;
}
bool SPIRVLowerMemmoveBase::runLowerMemmove(Module &M) {
Context = &M.getContext();
bool Changed = false;
for (Function &F : M) {
if (!F.isDeclaration())
continue;
if (F.getIntrinsicID() == Intrinsic::memmove)
Changed |= expandMemMoveIntrinsicUses(F);
}
verifyRegularizationPass(M, "SPIRVLowerMemmove");
return Changed;
}
llvm::PreservedAnalyses
SPIRVLowerMemmovePass::run(llvm::Module &M, llvm::ModuleAnalysisManager &MAM) {
return runLowerMemmove(M) ? llvm::PreservedAnalyses::none()
: llvm::PreservedAnalyses::all();
}
SPIRVLowerMemmoveLegacy::SPIRVLowerMemmoveLegacy() : ModulePass(ID) {
initializeSPIRVLowerMemmoveLegacyPass(*PassRegistry::getPassRegistry());
}
bool SPIRVLowerMemmoveLegacy::runOnModule(Module &M) {
return runLowerMemmove(M);
}
char SPIRVLowerMemmoveLegacy::ID = 0;
} // namespace SPIRV
INITIALIZE_PASS(SPIRVLowerMemmoveLegacy, "spvmemmove",
"Lower llvm.memmove into llvm.memcpy", false, false)
ModulePass *llvm::createSPIRVLowerMemmoveLegacy() {
return new SPIRVLowerMemmoveLegacy();
}