LLVM 22.0.0git
DXILMemIntrinsics.cpp
Go to the documentation of this file.
1//===- DXILMemIntrinsics.cpp - Eliminate Memory Intrinsics ----------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "DXILMemIntrinsics.h"
10#include "DirectX.h"
11#include "llvm/IR/IRBuilder.h"
13#include "llvm/IR/Module.h"
14
15#define DEBUG_TYPE "dxil-mem-intrinsics"
16
17using namespace llvm;
18
19void expandMemSet(MemSetInst *MemSet) {
20 IRBuilder<> Builder(MemSet);
21 Value *Dst = MemSet->getDest();
22 Value *Val = MemSet->getValue();
23 ConstantInt *LengthCI = dyn_cast<ConstantInt>(MemSet->getLength());
24 assert(LengthCI && "Expected length to be a ConstantInt");
25
26 [[maybe_unused]] const DataLayout &DL =
27 Builder.GetInsertBlock()->getModule()->getDataLayout();
28 [[maybe_unused]] uint64_t OrigLength = LengthCI->getZExtValue();
29
30 AllocaInst *Alloca = dyn_cast<AllocaInst>(Dst);
31
32 assert(Alloca && "Expected memset on an Alloca");
33 assert(OrigLength == Alloca->getAllocationSize(DL)->getFixedValue() &&
34 "Expected for memset size to match DataLayout size");
35
36 Type *AllocatedTy = Alloca->getAllocatedType();
37 ArrayType *ArrTy = dyn_cast<ArrayType>(AllocatedTy);
38 assert(ArrTy && "Expected Alloca for an Array Type");
39
40 Type *ElemTy = ArrTy->getElementType();
41 uint64_t Size = ArrTy->getArrayNumElements();
42
43 [[maybe_unused]] uint64_t ElemSize = DL.getTypeStoreSize(ElemTy);
44
45 assert(ElemSize > 0 && "Size must be set");
46 assert(OrigLength == ElemSize * Size && "Size in bytes must match");
47
48 Value *TypedVal = Val;
49
50 if (Val->getType() != ElemTy)
51 TypedVal = Builder.CreateIntCast(Val, ElemTy, false);
52
53 for (uint64_t I = 0; I < Size; ++I) {
54 Value *Zero = Builder.getInt32(0);
55 Value *Offset = Builder.getInt32(I);
56 Value *Ptr = Builder.CreateGEP(ArrTy, Dst, {Zero, Offset}, "gep");
57 Builder.CreateStore(TypedVal, Ptr);
58 }
59
60 MemSet->eraseFromParent();
61}
62
63void expandMemCpy(MemCpyInst *MemCpy) {
64 IRBuilder<> Builder(MemCpy);
65 Value *Dst = MemCpy->getDest();
66 Value *Src = MemCpy->getSource();
67 ConstantInt *LengthCI = dyn_cast<ConstantInt>(MemCpy->getLength());
68 assert(LengthCI && "Expected Length to be a ConstantInt");
69 assert(!MemCpy->isVolatile() && "Handling for volatile not implemented");
70
71 uint64_t ByteLength = LengthCI->getZExtValue();
72 // If length to copy is zero, no memcpy is needed.
73 if (ByteLength == 0)
74 return;
75
76 const DataLayout &DL = Builder.GetInsertBlock()->getModule()->getDataLayout();
77
78 auto GetArrTyFromVal = [](Value *Val) -> ArrayType * {
81 "Expected Val to be an Alloca or Global Variable");
82 if (auto *Alloca = dyn_cast<AllocaInst>(Val))
83 return dyn_cast<ArrayType>(Alloca->getAllocatedType());
84 if (auto *GlobalVar = dyn_cast<GlobalVariable>(Val))
85 return dyn_cast<ArrayType>(GlobalVar->getValueType());
86 return nullptr;
87 };
88
89 ArrayType *DstArrTy = GetArrTyFromVal(Dst);
90 assert(DstArrTy && "Expected Dst of memcpy to be a Pointer to an Array Type");
91 if (auto *DstGlobalVar = dyn_cast<GlobalVariable>(Dst))
92 assert(!DstGlobalVar->isConstant() &&
93 "The Dst of memcpy must not be a constant Global Variable");
94 [[maybe_unused]] ArrayType *SrcArrTy = GetArrTyFromVal(Src);
95 assert(SrcArrTy && "Expected Src of memcpy to be a Pointer to an Array Type");
96
97 Type *DstElemTy = DstArrTy->getElementType();
98 uint64_t DstElemByteSize = DL.getTypeStoreSize(DstElemTy);
99 assert(DstElemByteSize > 0 && "Dst element type store size must be set");
100 Type *SrcElemTy = SrcArrTy->getElementType();
101 [[maybe_unused]] uint64_t SrcElemByteSize = DL.getTypeStoreSize(SrcElemTy);
102 assert(SrcElemByteSize > 0 && "Src element type store size must be set");
103
104 // This assumption simplifies implementation and covers currently-known
105 // use-cases for DXIL. It may be relaxed in the future if required.
106 assert(DstElemTy == SrcElemTy &&
107 "The element types of Src and Dst arrays must match");
108
109 [[maybe_unused]] uint64_t DstArrNumElems = DstArrTy->getArrayNumElements();
110 assert(DstElemByteSize * DstArrNumElems >= ByteLength &&
111 "Dst array size must be at least as large as the memcpy length");
112 [[maybe_unused]] uint64_t SrcArrNumElems = SrcArrTy->getArrayNumElements();
113 assert(SrcElemByteSize * SrcArrNumElems >= ByteLength &&
114 "Src array size must be at least as large as the memcpy length");
115
116 uint64_t NumElemsToCopy = ByteLength / DstElemByteSize;
117 assert(ByteLength % DstElemByteSize == 0 &&
118 "memcpy length must be divisible by array element type");
119 for (uint64_t I = 0; I < NumElemsToCopy; ++I) {
120 SmallVector<Value *, 2> Indices = {Builder.getInt32(0),
121 Builder.getInt32(I)};
122 Value *SrcPtr = Builder.CreateInBoundsGEP(SrcArrTy, Src, Indices, "gep");
123 Value *SrcVal = Builder.CreateLoad(SrcElemTy, SrcPtr);
124 Value *DstPtr = Builder.CreateInBoundsGEP(DstArrTy, Dst, Indices, "gep");
125 Builder.CreateStore(SrcVal, DstPtr);
126 }
127
128 MemCpy->eraseFromParent();
129}
130
132 report_fatal_error("memmove expansion is not implemented yet.");
133}
134
136 bool HadMemIntrinsicUses = false;
137 for (auto &F : make_early_inc_range(M.functions())) {
138 Intrinsic::ID IID = F.getIntrinsicID();
139 switch (IID) {
140 case Intrinsic::memcpy:
141 case Intrinsic::memcpy_inline:
142 case Intrinsic::memmove:
143 case Intrinsic::memset:
144 case Intrinsic::memset_inline:
145 break;
146 default:
147 continue;
148 }
149 for (User *U : make_early_inc_range(F.users())) {
150 HadMemIntrinsicUses = true;
151 if (auto *MemSet = dyn_cast<MemSetInst>(U))
152 expandMemSet(MemSet);
153 else if (auto *MemCpy = dyn_cast<MemCpyInst>(U))
154 expandMemCpy(MemCpy);
155 else if (auto *MemMove = dyn_cast<MemMoveInst>(U))
156 expandMemMove(MemMove);
157 else
158 llvm_unreachable("Unhandled memory intrinsic");
159 }
160 assert(F.user_empty() && "Mem intrinsic not eliminated?");
161 F.eraseFromParent();
162 }
163 return HadMemIntrinsicUses;
164}
165
171
173public:
174 bool runOnModule(Module &M) override { return eliminateMemIntrinsics(M); }
176
177 static char ID; // Pass identification.
178};
180
182 "DXIL Memory Intrinsic Elimination", false, false)
184 "DXIL Memory Intrinsic Elimination", false, false)
185
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static bool eliminateMemIntrinsics(Module &M)
void expandMemSet(MemSetInst *MemSet)
void expandMemCpy(MemCpyInst *MemCpy)
void expandMemMove(MemMoveInst *MemMove)
#define DEBUG_TYPE
Module.h This file contains the declarations for the Module class.
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
Definition PassSupport.h:44
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
Definition PassSupport.h:39
bool runOnModule(Module &M) override
runOnModule - Virtual method overriden by subclasses to process the module being operated on.
an instruction to allocate memory on the stack
Type * getAllocatedType() const
Return the type that is being allocated by the instruction.
LLVM_ABI std::optional< TypeSize > getAllocationSize(const DataLayout &DL) const
Get allocation size in bytes.
This is the shared class of boolean and integer constants.
Definition Constants.h:87
uint64_t getZExtValue() const
Return the constant as a 64-bit unsigned integer value after it has been zero extended as appropriate...
Definition Constants.h:171
PreservedAnalyses run(Module &M, ModuleAnalysisManager &)
A parsed version of the target data layout string in and methods for querying it.
Definition DataLayout.h:64
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Definition IRBuilder.h:2788
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
This class wraps the llvm.memcpy intrinsic.
Value * getLength() const
Value * getDest() const
This is just like getRawDest, but it strips off any cast instructions (including addrspacecast) that ...
bool isVolatile() const
This class wraps the llvm.memmove intrinsic.
Value * getValue() const
This class wraps the llvm.memset and llvm.memset.inline intrinsics.
Value * getSource() const
This is just like getRawSource, but it strips off any cast instructions that feed it,...
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
Definition Pass.h:255
ModulePass(char &pid)
Definition Pass.h:257
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:67
A set of analyses that are preserved following a run of a transformation pass.
Definition Analysis.h:112
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
Definition Analysis.h:115
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:45
LLVM Value Representation.
Definition Value.h:75
Type * getType() const
All values are typed, get the type of this value.
Definition Value.h:256
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
This is an optimization pass for GlobalISel generic memory operations.
@ Offset
Definition DWP.cpp:532
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
Definition STLExtras.h:632
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:167
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
ModulePass * createDXILMemIntrinsicsLegacyPass()
Pass to transform all llvm memory intrinsics to explicit loads and stores.
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
Definition MIRParser.h:39