LLVM 22.0.0git
DXILLegalizePass.cpp
Go to the documentation of this file.
1//===- DXILLegalizePass.cpp - Legalizes llvm IR for DXIL ------------------===//
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 "DXILLegalizePass.h"
10#include "DirectX.h"
11#include "llvm/ADT/APInt.h"
12#include "llvm/IR/Constants.h"
13#include "llvm/IR/Function.h"
14#include "llvm/IR/IRBuilder.h"
16#include "llvm/IR/Instruction.h"
18#include "llvm/IR/Module.h"
19#include "llvm/Pass.h"
21#include <functional>
22
23#define DEBUG_TYPE "dxil-legalize"
24
25using namespace llvm;
26
30 auto *FI = dyn_cast<FreezeInst>(&I);
31 if (!FI)
32 return false;
33
34 FI->replaceAllUsesWith(FI->getOperand(0));
35 ToRemove.push_back(FI);
36 return true;
37}
38
41 DenseMap<Value *, Value *> &ReplacedValues) {
42
43 auto ProcessOperands = [&](SmallVector<Value *> &NewOperands) {
44 Type *InstrType = IntegerType::get(I.getContext(), 32);
45
46 for (unsigned OpIdx = 0; OpIdx < I.getNumOperands(); ++OpIdx) {
47 Value *Op = I.getOperand(OpIdx);
48 if (ReplacedValues.count(Op) &&
49 ReplacedValues[Op]->getType()->isIntegerTy())
50 InstrType = ReplacedValues[Op]->getType();
51 }
52
53 for (unsigned OpIdx = 0; OpIdx < I.getNumOperands(); ++OpIdx) {
54 Value *Op = I.getOperand(OpIdx);
55 if (ReplacedValues.count(Op))
56 NewOperands.push_back(ReplacedValues[Op]);
57 else if (auto *Imm = dyn_cast<ConstantInt>(Op)) {
58 APInt Value = Imm->getValue();
59 unsigned NewBitWidth = InstrType->getIntegerBitWidth();
60 // Note: options here are sext or sextOrTrunc.
61 // Since i8 isn't supported, we assume new values
62 // will always have a higher bitness.
63 assert(NewBitWidth > Value.getBitWidth() &&
64 "Replacement's BitWidth should be larger than Current.");
65 APInt NewValue = Value.sext(NewBitWidth);
66 NewOperands.push_back(ConstantInt::get(InstrType, NewValue));
67 } else {
68 assert(!Op->getType()->isIntegerTy(8));
69 NewOperands.push_back(Op);
70 }
71 }
72 };
73 IRBuilder<> Builder(&I);
74 if (auto *Trunc = dyn_cast<TruncInst>(&I)) {
75 if (Trunc->getDestTy()->isIntegerTy(8)) {
76 ReplacedValues[Trunc] = Trunc->getOperand(0);
77 ToRemove.push_back(Trunc);
78 return true;
79 }
80 }
81
82 if (auto *Store = dyn_cast<StoreInst>(&I)) {
83 if (!Store->getValueOperand()->getType()->isIntegerTy(8))
84 return false;
85 SmallVector<Value *> NewOperands;
86 ProcessOperands(NewOperands);
87 Value *NewStore = Builder.CreateStore(NewOperands[0], NewOperands[1]);
88 ReplacedValues[Store] = NewStore;
89 ToRemove.push_back(Store);
90 return true;
91 }
92
93 if (auto *Load = dyn_cast<LoadInst>(&I);
94 Load && I.getType()->isIntegerTy(8)) {
95 SmallVector<Value *> NewOperands;
96 ProcessOperands(NewOperands);
97 Type *ElementType = NewOperands[0]->getType();
98 if (auto *AI = dyn_cast<AllocaInst>(NewOperands[0]))
99 ElementType = AI->getAllocatedType();
100 if (auto *GEP = dyn_cast<GetElementPtrInst>(NewOperands[0])) {
101 ElementType = GEP->getSourceElementType();
102 }
103 if (ElementType->isArrayTy())
104 ElementType = ElementType->getArrayElementType();
105 LoadInst *NewLoad = Builder.CreateLoad(ElementType, NewOperands[0]);
106 ReplacedValues[Load] = NewLoad;
107 ToRemove.push_back(Load);
108 return true;
109 }
110
111 if (auto *Load = dyn_cast<LoadInst>(&I);
112 Load && isa<ConstantExpr>(Load->getPointerOperand())) {
113 auto *CE = dyn_cast<ConstantExpr>(Load->getPointerOperand());
114 if (!(CE->getOpcode() == Instruction::GetElementPtr))
115 return false;
116 auto *GEP = dyn_cast<GEPOperator>(CE);
117 if (!GEP->getSourceElementType()->isIntegerTy(8))
118 return false;
119
120 Type *ElementType = Load->getType();
121 ConstantInt *Offset = dyn_cast<ConstantInt>(GEP->getOperand(1));
122 uint32_t ByteOffset = Offset->getZExtValue();
123 uint32_t ElemSize = Load->getDataLayout().getTypeAllocSize(ElementType);
124 uint32_t Index = ByteOffset / ElemSize;
125
126 Value *PtrOperand = GEP->getPointerOperand();
127 Type *GEPType = GEP->getPointerOperandType();
128
129 if (auto *GV = dyn_cast<GlobalVariable>(PtrOperand))
130 GEPType = GV->getValueType();
131 if (auto *AI = dyn_cast<AllocaInst>(PtrOperand))
132 GEPType = AI->getAllocatedType();
133
134 if (auto *ArrTy = dyn_cast<ArrayType>(GEPType))
135 GEPType = ArrTy;
136 else
137 GEPType = ArrayType::get(ElementType, 1); // its a scalar
138
139 Value *NewGEP = Builder.CreateGEP(
140 GEPType, PtrOperand, {Builder.getInt32(0), Builder.getInt32(Index)},
141 GEP->getName(), GEP->getNoWrapFlags());
142
143 LoadInst *NewLoad = Builder.CreateLoad(ElementType, NewGEP);
144 ReplacedValues[Load] = NewLoad;
145 Load->replaceAllUsesWith(NewLoad);
146 ToRemove.push_back(Load);
147 return true;
148 }
149
150 if (auto *BO = dyn_cast<BinaryOperator>(&I)) {
151 if (!I.getType()->isIntegerTy(8))
152 return false;
153 SmallVector<Value *> NewOperands;
154 ProcessOperands(NewOperands);
155 Value *NewInst =
156 Builder.CreateBinOp(BO->getOpcode(), NewOperands[0], NewOperands[1]);
157 if (auto *OBO = dyn_cast<OverflowingBinaryOperator>(&I)) {
158 auto *NewBO = dyn_cast<BinaryOperator>(NewInst);
159 if (NewBO && OBO->hasNoSignedWrap())
160 NewBO->setHasNoSignedWrap();
161 if (NewBO && OBO->hasNoUnsignedWrap())
162 NewBO->setHasNoUnsignedWrap();
163 }
164 ReplacedValues[BO] = NewInst;
165 ToRemove.push_back(BO);
166 return true;
167 }
168
169 if (auto *Sel = dyn_cast<SelectInst>(&I)) {
170 if (!I.getType()->isIntegerTy(8))
171 return false;
172 SmallVector<Value *> NewOperands;
173 ProcessOperands(NewOperands);
174 Value *NewInst = Builder.CreateSelect(Sel->getCondition(), NewOperands[1],
175 NewOperands[2]);
176 ReplacedValues[Sel] = NewInst;
177 ToRemove.push_back(Sel);
178 return true;
179 }
180
181 if (auto *Cmp = dyn_cast<CmpInst>(&I)) {
182 if (!Cmp->getOperand(0)->getType()->isIntegerTy(8))
183 return false;
184 SmallVector<Value *> NewOperands;
185 ProcessOperands(NewOperands);
186 Value *NewInst =
187 Builder.CreateCmp(Cmp->getPredicate(), NewOperands[0], NewOperands[1]);
188 Cmp->replaceAllUsesWith(NewInst);
189 ReplacedValues[Cmp] = NewInst;
190 ToRemove.push_back(Cmp);
191 return true;
192 }
193
194 if (auto *Cast = dyn_cast<CastInst>(&I)) {
195 if (!Cast->getSrcTy()->isIntegerTy(8))
196 return false;
197
198 ToRemove.push_back(Cast);
199 auto *Replacement = ReplacedValues[Cast->getOperand(0)];
200 if (Cast->getType() == Replacement->getType()) {
201 Cast->replaceAllUsesWith(Replacement);
202 return true;
203 }
204
205 Value *AdjustedCast = nullptr;
206 if (Cast->getOpcode() == Instruction::ZExt)
207 AdjustedCast = Builder.CreateZExtOrTrunc(Replacement, Cast->getType());
208 if (Cast->getOpcode() == Instruction::SExt)
209 AdjustedCast = Builder.CreateSExtOrTrunc(Replacement, Cast->getType());
210
211 if (AdjustedCast)
212 Cast->replaceAllUsesWith(AdjustedCast);
213 }
214 if (auto *GEP = dyn_cast<GetElementPtrInst>(&I)) {
215 if (!GEP->getType()->isPointerTy() ||
216 !GEP->getSourceElementType()->isIntegerTy(8))
217 return false;
218
219 Value *BasePtr = GEP->getPointerOperand();
220 if (ReplacedValues.count(BasePtr))
221 BasePtr = ReplacedValues[BasePtr];
222
223 Type *ElementType = BasePtr->getType();
224
225 if (auto *AI = dyn_cast<AllocaInst>(BasePtr))
226 ElementType = AI->getAllocatedType();
227 if (auto *GV = dyn_cast<GlobalVariable>(BasePtr))
228 ElementType = GV->getValueType();
229
230 Type *GEPType = ElementType;
231 if (auto *ArrTy = dyn_cast<ArrayType>(ElementType))
232 ElementType = ArrTy->getArrayElementType();
233 else
234 GEPType = ArrayType::get(ElementType, 1); // its a scalar
235
236 ConstantInt *Offset = dyn_cast<ConstantInt>(GEP->getOperand(1));
237 // Note: i8 to i32 offset conversion without emitting IR requires constant
238 // ints. Since offset conversion is common, we can safely assume Offset is
239 // always a ConstantInt, so no need to have a conditional bail out on
240 // nullptr, instead assert this is the case.
241 assert(Offset && "Offset is expected to be a ConstantInt");
242 uint32_t ByteOffset = Offset->getZExtValue();
243 uint32_t ElemSize = GEP->getDataLayout().getTypeAllocSize(ElementType);
244 assert(ElemSize > 0 && "ElementSize must be set");
245 uint32_t Index = ByteOffset / ElemSize;
246 Value *NewGEP = Builder.CreateGEP(
247 GEPType, BasePtr, {Builder.getInt32(0), Builder.getInt32(Index)},
248 GEP->getName(), GEP->getNoWrapFlags());
249 ReplacedValues[GEP] = NewGEP;
250 GEP->replaceAllUsesWith(NewGEP);
251 ToRemove.push_back(GEP);
252 return true;
253 }
254 return false;
255}
256
259 DenseMap<Value *, Value *> &ReplacedValues) {
260 auto *AI = dyn_cast<AllocaInst>(&I);
261 if (!AI || !AI->getAllocatedType()->isIntegerTy(8))
262 return false;
263
264 Type *SmallestType = nullptr;
265
266 auto ProcessLoad = [&](LoadInst *Load) {
267 for (User *LU : Load->users()) {
268 Type *Ty = nullptr;
269 if (CastInst *Cast = dyn_cast<CastInst>(LU))
270 Ty = Cast->getType();
271 else if (CallInst *CI = dyn_cast<CallInst>(LU)) {
272 if (CI->getIntrinsicID() == Intrinsic::memset)
273 Ty = Type::getInt32Ty(CI->getContext());
274 }
275
276 if (!Ty)
277 continue;
278
279 if (!SmallestType ||
280 Ty->getPrimitiveSizeInBits() < SmallestType->getPrimitiveSizeInBits())
281 SmallestType = Ty;
282 }
283 };
284
285 for (User *U : AI->users()) {
286 if (auto *Load = dyn_cast<LoadInst>(U))
287 ProcessLoad(Load);
288 else if (auto *GEP = dyn_cast<GetElementPtrInst>(U)) {
289 for (User *GU : GEP->users()) {
290 if (auto *Load = dyn_cast<LoadInst>(GU))
291 ProcessLoad(Load);
292 }
293 }
294 }
295
296 if (!SmallestType)
297 return false; // no valid casts found
298
299 // Replace alloca
300 IRBuilder<> Builder(AI);
301 auto *NewAlloca = Builder.CreateAlloca(SmallestType);
302 ReplacedValues[AI] = NewAlloca;
303 ToRemove.push_back(AI);
304 return true;
305}
306
307static bool
311
312 if (auto *Extract = dyn_cast<ExtractElementInst>(&I)) {
313 Value *Idx = Extract->getIndexOperand();
314 auto *CI = dyn_cast<ConstantInt>(Idx);
315 if (CI && CI->getBitWidth() == 64) {
316 IRBuilder<> Builder(Extract);
317 int64_t IndexValue = CI->getSExtValue();
318 auto *Idx32 =
319 ConstantInt::get(Type::getInt32Ty(I.getContext()), IndexValue);
320 Value *NewExtract = Builder.CreateExtractElement(
321 Extract->getVectorOperand(), Idx32, Extract->getName());
322
323 Extract->replaceAllUsesWith(NewExtract);
324 ToRemove.push_back(Extract);
325 return true;
326 }
327 }
328
329 if (auto *Insert = dyn_cast<InsertElementInst>(&I)) {
330 Value *Idx = Insert->getOperand(2);
331 auto *CI = dyn_cast<ConstantInt>(Idx);
332 if (CI && CI->getBitWidth() == 64) {
333 int64_t IndexValue = CI->getSExtValue();
334 auto *Idx32 =
335 ConstantInt::get(Type::getInt32Ty(I.getContext()), IndexValue);
336 IRBuilder<> Builder(Insert);
337 Value *Insert32Index = Builder.CreateInsertElement(
338 Insert->getOperand(0), Insert->getOperand(1), Idx32,
339 Insert->getName());
340
341 Insert->replaceAllUsesWith(Insert32Index);
342 ToRemove.push_back(Insert);
343 return true;
344 }
345 }
346 return false;
347}
348
349static void emitMemcpyExpansion(IRBuilder<> &Builder, Value *Dst, Value *Src,
351
352 uint64_t ByteLength = Length->getZExtValue();
353 // If length to copy is zero, no memcpy is needed.
354 if (ByteLength == 0)
355 return;
356
357 const DataLayout &DL = Builder.GetInsertBlock()->getModule()->getDataLayout();
358
359 auto GetArrTyFromVal = [](Value *Val) -> ArrayType * {
360 assert(isa<AllocaInst>(Val) ||
361 isa<GlobalVariable>(Val) &&
362 "Expected Val to be an Alloca or Global Variable");
363 if (auto *Alloca = dyn_cast<AllocaInst>(Val))
364 return dyn_cast<ArrayType>(Alloca->getAllocatedType());
365 if (auto *GlobalVar = dyn_cast<GlobalVariable>(Val))
366 return dyn_cast<ArrayType>(GlobalVar->getValueType());
367 return nullptr;
368 };
369
370 ArrayType *DstArrTy = GetArrTyFromVal(Dst);
371 assert(DstArrTy && "Expected Dst of memcpy to be a Pointer to an Array Type");
372 if (auto *DstGlobalVar = dyn_cast<GlobalVariable>(Dst))
373 assert(!DstGlobalVar->isConstant() &&
374 "The Dst of memcpy must not be a constant Global Variable");
375 [[maybe_unused]] ArrayType *SrcArrTy = GetArrTyFromVal(Src);
376 assert(SrcArrTy && "Expected Src of memcpy to be a Pointer to an Array Type");
377
378 Type *DstElemTy = DstArrTy->getElementType();
379 uint64_t DstElemByteSize = DL.getTypeStoreSize(DstElemTy);
380 assert(DstElemByteSize > 0 && "Dst element type store size must be set");
381 Type *SrcElemTy = SrcArrTy->getElementType();
382 [[maybe_unused]] uint64_t SrcElemByteSize = DL.getTypeStoreSize(SrcElemTy);
383 assert(SrcElemByteSize > 0 && "Src element type store size must be set");
384
385 // This assumption simplifies implementation and covers currently-known
386 // use-cases for DXIL. It may be relaxed in the future if required.
387 assert(DstElemTy == SrcElemTy &&
388 "The element types of Src and Dst arrays must match");
389
390 [[maybe_unused]] uint64_t DstArrNumElems = DstArrTy->getArrayNumElements();
391 assert(DstElemByteSize * DstArrNumElems >= ByteLength &&
392 "Dst array size must be at least as large as the memcpy length");
393 [[maybe_unused]] uint64_t SrcArrNumElems = SrcArrTy->getArrayNumElements();
394 assert(SrcElemByteSize * SrcArrNumElems >= ByteLength &&
395 "Src array size must be at least as large as the memcpy length");
396
397 uint64_t NumElemsToCopy = ByteLength / DstElemByteSize;
398 assert(ByteLength % DstElemByteSize == 0 &&
399 "memcpy length must be divisible by array element type");
400 for (uint64_t I = 0; I < NumElemsToCopy; ++I) {
401 SmallVector<Value *, 2> Indices = {Builder.getInt32(0),
402 Builder.getInt32(I)};
403 Value *SrcPtr = Builder.CreateInBoundsGEP(SrcArrTy, Src, Indices, "gep");
404 Value *SrcVal = Builder.CreateLoad(SrcElemTy, SrcPtr);
405 Value *DstPtr = Builder.CreateInBoundsGEP(DstArrTy, Dst, Indices, "gep");
406 Builder.CreateStore(SrcVal, DstPtr);
407 }
408}
409
410static void emitMemsetExpansion(IRBuilder<> &Builder, Value *Dst, Value *Val,
411 ConstantInt *SizeCI,
412 DenseMap<Value *, Value *> &ReplacedValues) {
413 [[maybe_unused]] const DataLayout &DL =
414 Builder.GetInsertBlock()->getModule()->getDataLayout();
415 [[maybe_unused]] uint64_t OrigSize = SizeCI->getZExtValue();
416
417 AllocaInst *Alloca = dyn_cast<AllocaInst>(Dst);
418
419 assert(Alloca && "Expected memset on an Alloca");
420 assert(OrigSize == Alloca->getAllocationSize(DL)->getFixedValue() &&
421 "Expected for memset size to match DataLayout size");
422
423 Type *AllocatedTy = Alloca->getAllocatedType();
424 ArrayType *ArrTy = dyn_cast<ArrayType>(AllocatedTy);
425 assert(ArrTy && "Expected Alloca for an Array Type");
426
427 Type *ElemTy = ArrTy->getElementType();
428 uint64_t Size = ArrTy->getArrayNumElements();
429
430 [[maybe_unused]] uint64_t ElemSize = DL.getTypeStoreSize(ElemTy);
431
432 assert(ElemSize > 0 && "Size must be set");
433 assert(OrigSize == ElemSize * Size && "Size in bytes must match");
434
435 Value *TypedVal = Val;
436
437 if (Val->getType() != ElemTy) {
438 if (ReplacedValues[Val]) {
439 // Note for i8 replacements if we know them we should use them.
440 // Further if this is a constant ReplacedValues will return null
441 // so we will stick to TypedVal = Val
442 TypedVal = ReplacedValues[Val];
443
444 } else {
445 // This case Val is a ConstantInt so the cast folds away.
446 // However if we don't do the cast the store below ends up being
447 // an i8.
448 TypedVal = Builder.CreateIntCast(Val, ElemTy, false);
449 }
450 }
451
452 for (uint64_t I = 0; I < Size; ++I) {
453 Value *Zero = Builder.getInt32(0);
454 Value *Offset = Builder.getInt32(I);
455 Value *Ptr = Builder.CreateGEP(ArrTy, Dst, {Zero, Offset}, "gep");
456 Builder.CreateStore(TypedVal, Ptr);
457 }
458}
459
460// Expands the instruction `I` into corresponding loads and stores if it is a
461// memcpy call. In that case, the call instruction is added to the `ToRemove`
462// vector. `ReplacedValues` is unused.
465 DenseMap<Value *, Value *> &ReplacedValues) {
466
467 CallInst *CI = dyn_cast<CallInst>(&I);
468 if (!CI)
469 return false;
470
472 if (ID != Intrinsic::memcpy)
473 return false;
474
475 IRBuilder<> Builder(&I);
476 Value *Dst = CI->getArgOperand(0);
477 Value *Src = CI->getArgOperand(1);
478 ConstantInt *Length = dyn_cast<ConstantInt>(CI->getArgOperand(2));
479 assert(Length && "Expected Length to be a ConstantInt");
480 [[maybe_unused]] ConstantInt *IsVolatile =
481 dyn_cast<ConstantInt>(CI->getArgOperand(3));
482 assert(IsVolatile && "Expected IsVolatile to be a ConstantInt");
483 assert(IsVolatile->getZExtValue() == 0 && "Expected IsVolatile to be false");
484 emitMemcpyExpansion(Builder, Dst, Src, Length);
485 ToRemove.push_back(CI);
486 return true;
487}
488
491 DenseMap<Value *, Value *> &ReplacedValues) {
492
493 CallInst *CI = dyn_cast<CallInst>(&I);
494 if (!CI)
495 return false;
496
498 if (ID != Intrinsic::memset)
499 return false;
500
501 IRBuilder<> Builder(&I);
502 Value *Dst = CI->getArgOperand(0);
503 Value *Val = CI->getArgOperand(1);
504 ConstantInt *Size = dyn_cast<ConstantInt>(CI->getArgOperand(2));
505 assert(Size && "Expected Size to be a ConstantInt");
506 emitMemsetExpansion(Builder, Dst, Val, Size, ReplacedValues);
507 ToRemove.push_back(CI);
508 return true;
509}
510
514 const Intrinsic::ID ID = I.getOpcode();
515 if (ID != Instruction::FNeg)
516 return false;
517
518 IRBuilder<> Builder(&I);
519 Value *In = I.getOperand(0);
520 Value *Zero = ConstantFP::get(In->getType(), -0.0);
521 I.replaceAllUsesWith(Builder.CreateFSub(Zero, In));
522 ToRemove.push_back(&I);
523 return true;
524}
525
526static bool
529 DenseMap<Value *, Value *> &ReplacedValues) {
530 if (auto *BitCast = dyn_cast<BitCastInst>(&I)) {
531 if (BitCast->getDestTy() ==
532 FixedVectorType::get(Type::getInt32Ty(I.getContext()), 2) &&
533 BitCast->getSrcTy()->isIntegerTy(64)) {
534 ToRemove.push_back(BitCast);
535 ReplacedValues[BitCast] = BitCast->getOperand(0);
536 return true;
537 }
538 }
539
540 if (auto *Extract = dyn_cast<ExtractElementInst>(&I)) {
541 if (!dyn_cast<BitCastInst>(Extract->getVectorOperand()))
542 return false;
543 auto *VecTy = dyn_cast<FixedVectorType>(Extract->getVectorOperandType());
544 if (VecTy && VecTy->getElementType()->isIntegerTy(32) &&
545 VecTy->getNumElements() == 2) {
546 if (auto *Index = dyn_cast<ConstantInt>(Extract->getIndexOperand())) {
547 unsigned Idx = Index->getZExtValue();
548 IRBuilder<> Builder(&I);
549
550 auto *Replacement = ReplacedValues[Extract->getVectorOperand()];
551 assert(Replacement && "The BitCast replacement should have been set "
552 "before working on ExtractElementInst.");
553 if (Idx == 0) {
554 Value *LowBytes = Builder.CreateTrunc(
555 Replacement, Type::getInt32Ty(I.getContext()));
556 ReplacedValues[Extract] = LowBytes;
557 } else {
558 assert(Idx == 1);
559 Value *LogicalShiftRight = Builder.CreateLShr(
560 Replacement,
561 ConstantInt::get(
562 Replacement->getType(),
563 APInt(Replacement->getType()->getIntegerBitWidth(), 32)));
564 Value *HighBytes = Builder.CreateTrunc(
565 LogicalShiftRight, Type::getInt32Ty(I.getContext()));
566 ReplacedValues[Extract] = HighBytes;
567 }
568 ToRemove.push_back(Extract);
569 Extract->replaceAllUsesWith(ReplacedValues[Extract]);
570 return true;
571 }
572 }
573 }
574 return false;
575}
576
577static bool
581
582 Value *PtrOp;
583 unsigned PtrOpIndex;
584 [[maybe_unused]] Type *LoadStoreTy;
585 if (auto *LI = dyn_cast<LoadInst>(&I)) {
586 PtrOp = LI->getPointerOperand();
587 PtrOpIndex = LI->getPointerOperandIndex();
588 LoadStoreTy = LI->getType();
589 } else if (auto *SI = dyn_cast<StoreInst>(&I)) {
590 PtrOp = SI->getPointerOperand();
591 PtrOpIndex = SI->getPointerOperandIndex();
592 LoadStoreTy = SI->getValueOperand()->getType();
593 } else
594 return false;
595
596 // If the load/store is not of a single-value type (i.e., scalar or vector)
597 // then we do not modify it. It shouldn't be a vector either because the
598 // dxil-data-scalarization pass is expected to run before this, but it's not
599 // incorrect to apply this transformation to vector load/stores.
600 if (!LoadStoreTy->isSingleValueType())
601 return false;
602
603 Type *ArrayTy;
604 if (auto *GlobalVarPtrOp = dyn_cast<GlobalVariable>(PtrOp))
605 ArrayTy = GlobalVarPtrOp->getValueType();
606 else if (auto *AllocaPtrOp = dyn_cast<AllocaInst>(PtrOp))
607 ArrayTy = AllocaPtrOp->getAllocatedType();
608 else
609 return false;
610
611 if (!isa<ArrayType>(ArrayTy))
612 return false;
613
614 assert(ArrayTy->getArrayElementType() == LoadStoreTy &&
615 "Expected array element type to be the same as to the scalar load or "
616 "store type");
617
618 Value *Zero = ConstantInt::get(Type::getInt32Ty(I.getContext()), 0);
620 ArrayTy, PtrOp, {Zero, Zero}, GEPNoWrapFlags::all(), "", I.getIterator());
621 I.setOperand(PtrOpIndex, GEP);
622 return true;
623}
624
625namespace {
626class DXILLegalizationPipeline {
627
628public:
629 DXILLegalizationPipeline() { initializeLegalizationPipeline(); }
630
631 bool runLegalizationPipeline(Function &F) {
632 bool MadeChange = false;
634 DenseMap<Value *, Value *> ReplacedValues;
635 for (int Stage = 0; Stage < NumStages; ++Stage) {
636 ToRemove.clear();
637 ReplacedValues.clear();
638 for (auto &I : instructions(F)) {
639 for (auto &LegalizationFn : LegalizationPipeline[Stage])
640 MadeChange |= LegalizationFn(I, ToRemove, ReplacedValues);
641 }
642
643 for (auto *Inst : reverse(ToRemove))
644 Inst->eraseFromParent();
645 }
646 return MadeChange;
647 }
648
649private:
650 enum LegalizationStage { Stage1 = 0, Stage2 = 1, NumStages };
651
652 using LegalizationFnTy =
655
656 SmallVector<LegalizationFnTy> LegalizationPipeline[NumStages];
657
658 void initializeLegalizationPipeline() {
659 LegalizationPipeline[Stage1].push_back(upcastI8AllocasAndUses);
660 LegalizationPipeline[Stage1].push_back(fixI8UseChain);
661 LegalizationPipeline[Stage1].push_back(legalizeGetHighLowi64Bytes);
662 LegalizationPipeline[Stage1].push_back(legalizeFreeze);
663 LegalizationPipeline[Stage1].push_back(legalizeMemCpy);
664 LegalizationPipeline[Stage1].push_back(legalizeMemSet);
665 LegalizationPipeline[Stage1].push_back(updateFnegToFsub);
666 // Note: legalizeGetHighLowi64Bytes and
667 // downcastI64toI32InsertExtractElements both modify extractelement, so they
668 // must run staggered stages. legalizeGetHighLowi64Bytes runs first b\c it
669 // removes extractelements, reducing the number that
670 // downcastI64toI32InsertExtractElements needs to handle.
671 LegalizationPipeline[Stage2].push_back(
673 LegalizationPipeline[Stage2].push_back(legalizeScalarLoadStoreOnArrays);
674 }
675};
676
677class DXILLegalizeLegacy : public FunctionPass {
678
679public:
680 bool runOnFunction(Function &F) override;
681 DXILLegalizeLegacy() : FunctionPass(ID) {}
682
683 static char ID; // Pass identification.
684};
685} // namespace
686
689 DXILLegalizationPipeline DXLegalize;
690 bool MadeChanges = DXLegalize.runLegalizationPipeline(F);
691 if (!MadeChanges)
692 return PreservedAnalyses::all();
694 return PA;
695}
696
697bool DXILLegalizeLegacy::runOnFunction(Function &F) {
698 DXILLegalizationPipeline DXLegalize;
699 return DXLegalize.runLegalizationPipeline(F);
700}
701
702char DXILLegalizeLegacy::ID = 0;
703
704INITIALIZE_PASS_BEGIN(DXILLegalizeLegacy, DEBUG_TYPE, "DXIL Legalizer", false,
705 false)
706INITIALIZE_PASS_END(DXILLegalizeLegacy, DEBUG_TYPE, "DXIL Legalizer", false,
707 false)
708
710 return new DXILLegalizeLegacy();
711}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file implements a class to represent arbitrary precision integral constant values and operations...
ReachingDefAnalysis InstSet & ToRemove
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Expand Atomic instructions
This file contains the declarations for the subclasses of Constant, which represent the different fla...
static bool fixI8UseChain(Instruction &I, SmallVectorImpl< Instruction * > &ToRemove, DenseMap< Value *, Value * > &ReplacedValues)
static bool downcastI64toI32InsertExtractElements(Instruction &I, SmallVectorImpl< Instruction * > &ToRemove, DenseMap< Value *, Value * > &)
static void emitMemcpyExpansion(IRBuilder<> &Builder, Value *Dst, Value *Src, ConstantInt *Length)
static bool upcastI8AllocasAndUses(Instruction &I, SmallVectorImpl< Instruction * > &ToRemove, DenseMap< Value *, Value * > &ReplacedValues)
static bool legalizeMemCpy(Instruction &I, SmallVectorImpl< Instruction * > &ToRemove, DenseMap< Value *, Value * > &ReplacedValues)
static bool legalizeMemSet(Instruction &I, SmallVectorImpl< Instruction * > &ToRemove, DenseMap< Value *, Value * > &ReplacedValues)
static void emitMemsetExpansion(IRBuilder<> &Builder, Value *Dst, Value *Val, ConstantInt *SizeCI, DenseMap< Value *, Value * > &ReplacedValues)
static bool legalizeScalarLoadStoreOnArrays(Instruction &I, SmallVectorImpl< Instruction * > &ToRemove, DenseMap< Value *, Value * > &)
static bool legalizeGetHighLowi64Bytes(Instruction &I, SmallVectorImpl< Instruction * > &ToRemove, DenseMap< Value *, Value * > &ReplacedValues)
static bool legalizeFreeze(Instruction &I, SmallVectorImpl< Instruction * > &ToRemove, DenseMap< Value *, Value * >)
static bool updateFnegToFsub(Instruction &I, SmallVectorImpl< Instruction * > &ToRemove, DenseMap< Value *, Value * > &)
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
uint64_t Size
#define DEBUG_TYPE
Hexagon Common GEP
Module.h This file contains the declarations for the Module class.
#define F(x, y, z)
Definition: MD5.cpp:55
#define I(x, y, z)
Definition: MD5.cpp:58
MachineInstr unsigned OpIdx
FunctionAnalysisManager FAM
#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
Class for arbitrary precision integers.
Definition: APInt.h:78
an instruction to allocate memory on the stack
Definition: Instructions.h:64
Type * getAllocatedType() const
Return the type that is being allocated by the instruction.
Definition: Instructions.h:121
LLVM_ABI std::optional< TypeSize > getAllocationSize(const DataLayout &DL) const
Get allocation size in bytes.
A container for analyses that lazily runs them and caches their results.
Definition: PassManager.h:255
LLVM_ABI const Module * getModule() const
Return the module owning the function this basic block belongs to, or nullptr if the function does no...
Definition: BasicBlock.cpp:248
Value * getArgOperand(unsigned i) const
Definition: InstrTypes.h:1292
LLVM_ABI Intrinsic::ID getIntrinsicID() const
Returns the intrinsic ID of the intrinsic called or Intrinsic::not_intrinsic if the called function i...
This class represents a function call, abstracting a target machine's calling convention.
This is the base class for all instructions that perform data casts.
Definition: InstrTypes.h:448
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:163
This class represents an Operation in the Expression.
PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM)
A parsed version of the target data layout string in and methods for querying it.
Definition: DataLayout.h:63
size_type count(const_arg_type_t< KeyT > Val) const
Return 1 if the specified key is in the map, 0 otherwise.
Definition: DenseMap.h:173
static LLVM_ABI FixedVectorType * get(Type *ElementType, unsigned NumElts)
Definition: Type.cpp:803
FunctionPass class - This class is used to implement most global optimizations.
Definition: Pass.h:314
virtual bool runOnFunction(Function &F)=0
runOnFunction - Virtual method overriden by subclasses to do the per-function processing of the pass.
static GEPNoWrapFlags all()
static GetElementPtrInst * Create(Type *PointeeType, Value *Ptr, ArrayRef< Value * > IdxList, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)
Definition: Instructions.h:973
Value * CreateFSub(Value *L, Value *R, const Twine &Name="", MDNode *FPMD=nullptr)
Definition: IRBuilder.h:1632
Value * CreateInsertElement(Type *VecTy, Value *NewElt, Value *Idx, const Twine &Name="")
Definition: IRBuilder.h:2571
AllocaInst * CreateAlloca(Type *Ty, unsigned AddrSpace, Value *ArraySize=nullptr, const Twine &Name="")
Definition: IRBuilder.h:1830
Value * CreateExtractElement(Value *Vec, Value *Idx, const Twine &Name="")
Definition: IRBuilder.h:2559
Value * CreateZExtOrTrunc(Value *V, Type *DestTy, const Twine &Name="")
Create a ZExt or Trunc from the integer value V to DestTy.
Definition: IRBuilder.h:2100
LLVM_ABI Value * CreateSelect(Value *C, Value *True, Value *False, const Twine &Name="", Instruction *MDFrom=nullptr)
Definition: IRBuilder.cpp:1005
Value * CreateLShr(Value *LHS, Value *RHS, const Twine &Name="", bool isExact=false)
Definition: IRBuilder.h:1513
BasicBlock * GetInsertBlock() const
Definition: IRBuilder.h:201
Value * CreateInBoundsGEP(Type *Ty, Value *Ptr, ArrayRef< Value * > IdxList, const Twine &Name="")
Definition: IRBuilder.h:1931
Value * CreateGEP(Type *Ty, Value *Ptr, ArrayRef< Value * > IdxList, const Twine &Name="", GEPNoWrapFlags NW=GEPNoWrapFlags::none())
Definition: IRBuilder.h:1923
ConstantInt * getInt32(uint32_t C)
Get a constant 32-bit value.
Definition: IRBuilder.h:522
Value * CreateCmp(CmpInst::Predicate Pred, Value *LHS, Value *RHS, const Twine &Name="", MDNode *FPMathTag=nullptr)
Definition: IRBuilder.h:2463
LoadInst * CreateLoad(Type *Ty, Value *Ptr, const char *Name)
Provided to resolve 'CreateLoad(Ty, Ptr, "...")' correctly, instead of converting the string to 'bool...
Definition: IRBuilder.h:1847
StoreInst * CreateStore(Value *Val, Value *Ptr, bool isVolatile=false)
Definition: IRBuilder.h:1860
Value * CreateTrunc(Value *V, Type *DestTy, const Twine &Name="", bool IsNUW=false, bool IsNSW=false)
Definition: IRBuilder.h:2068
Value * CreateBinOp(Instruction::BinaryOps Opc, Value *LHS, Value *RHS, const Twine &Name="", MDNode *FPMathTag=nullptr)
Definition: IRBuilder.h:1708
Value * CreateIntCast(Value *V, Type *DestTy, bool isSigned, const Twine &Name="")
Definition: IRBuilder.h:2277
Value * CreateSExtOrTrunc(Value *V, Type *DestTy, const Twine &Name="")
Create a SExt or Trunc from the integer value V to DestTy.
Definition: IRBuilder.h:2115
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Definition: IRBuilder.h:2780
static LLVM_ABI IntegerType * get(LLVMContext &C, unsigned NumBits)
This static method is the primary way of constructing an IntegerType.
Definition: Type.cpp:319
An instruction for reading from memory.
Definition: Instructions.h:180
const DataLayout & getDataLayout() const
Get the data layout for the module's target platform.
Definition: Module.h:278
A set of analyses that are preserved following a run of a transformation pass.
Definition: Analysis.h:112
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition: Analysis.h:118
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
Definition: SmallVector.h:574
void push_back(const T &Elt)
Definition: SmallVector.h:414
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1197
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
LLVM_ABI TypeSize getPrimitiveSizeInBits() const LLVM_READONLY
Return the basic size of this type if it is a primitive type.
static LLVM_ABI IntegerType * getInt32Ty(LLVMContext &C)
Type * getArrayElementType() const
Definition: Type.h:408
bool isSingleValueType() const
Return true if the type is a valid type for a register in codegen.
Definition: Type.h:296
bool isIntegerTy() const
True if this is an instance of IntegerType.
Definition: Type.h:240
LLVM Value Representation.
Definition: Value.h:75
Type * getType() const
All values are typed, get the type of this value.
Definition: Value.h:256
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
Definition: Value.cpp:546
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition: CallingConv.h:24
InstrType
This represents what is and is not supported when finding similarity in Instructions.
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
@ Offset
Definition: DWP.cpp:477
@ Length
Definition: DWP.cpp:477
FunctionPass * createDXILLegalizeLegacyPass()
Pass to Legalize DXIL by remove i8 truncations and i64 insert/extract elements.
auto reverse(ContainerTy &&C)
Definition: STLExtras.h:428
DWARFExpression::Operation Op