162 lines
5.9 KiB
C++
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();
|
|
}
|