1 //===- MVEGatherScatterLowering.cpp - Gather/Scatter lowering -------------===// 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 /// This pass custom lowers llvm.gather and llvm.scatter instructions to 10 /// arm.mve.gather and arm.mve.scatter intrinsics, optimising the code to 11 /// produce a better final result as we go. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #include "ARM.h" 16 #include "ARMBaseInstrInfo.h" 17 #include "ARMSubtarget.h" 18 #include "llvm/Analysis/LoopInfo.h" 19 #include "llvm/Analysis/TargetTransformInfo.h" 20 #include "llvm/CodeGen/TargetLowering.h" 21 #include "llvm/CodeGen/TargetPassConfig.h" 22 #include "llvm/CodeGen/TargetSubtargetInfo.h" 23 #include "llvm/InitializePasses.h" 24 #include "llvm/IR/BasicBlock.h" 25 #include "llvm/IR/Constant.h" 26 #include "llvm/IR/Constants.h" 27 #include "llvm/IR/DerivedTypes.h" 28 #include "llvm/IR/Function.h" 29 #include "llvm/IR/InstrTypes.h" 30 #include "llvm/IR/Instruction.h" 31 #include "llvm/IR/Instructions.h" 32 #include "llvm/IR/IntrinsicInst.h" 33 #include "llvm/IR/Intrinsics.h" 34 #include "llvm/IR/IntrinsicsARM.h" 35 #include "llvm/IR/IRBuilder.h" 36 #include "llvm/IR/PatternMatch.h" 37 #include "llvm/IR/Type.h" 38 #include "llvm/IR/Value.h" 39 #include "llvm/Pass.h" 40 #include "llvm/Support/Casting.h" 41 #include "llvm/Transforms/Utils/Local.h" 42 #include <algorithm> 43 #include <cassert> 44 45 using namespace llvm; 46 47 #define DEBUG_TYPE "arm-mve-gather-scatter-lowering" 48 49 cl::opt<bool> EnableMaskedGatherScatters( 50 "enable-arm-maskedgatscat", cl::Hidden, cl::init(true), 51 cl::desc("Enable the generation of masked gathers and scatters")); 52 53 namespace { 54 55 class MVEGatherScatterLowering : public FunctionPass { 56 public: 57 static char ID; // Pass identification, replacement for typeid 58 59 explicit MVEGatherScatterLowering() : FunctionPass(ID) { 60 initializeMVEGatherScatterLoweringPass(*PassRegistry::getPassRegistry()); 61 } 62 63 bool runOnFunction(Function &F) override; 64 65 StringRef getPassName() const override { 66 return "MVE gather/scatter lowering"; 67 } 68 69 void getAnalysisUsage(AnalysisUsage &AU) const override { 70 AU.setPreservesCFG(); 71 AU.addRequired<TargetPassConfig>(); 72 AU.addRequired<LoopInfoWrapperPass>(); 73 FunctionPass::getAnalysisUsage(AU); 74 } 75 76 private: 77 LoopInfo *LI = nullptr; 78 79 // Check this is a valid gather with correct alignment 80 bool isLegalTypeAndAlignment(unsigned NumElements, unsigned ElemSize, 81 Align Alignment); 82 // Check whether Ptr is hidden behind a bitcast and look through it 83 void lookThroughBitcast(Value *&Ptr); 84 // Decompose a ptr into Base and Offsets, potentially using a GEP to return a 85 // scalar base and vector offsets, or else fallback to using a base of 0 and 86 // offset of Ptr where possible. 87 Value *decomposePtr(Value *Ptr, Value *&Offsets, int &Scale, 88 FixedVectorType *Ty, Type *MemoryTy, 89 IRBuilder<> &Builder); 90 // Check for a getelementptr and deduce base and offsets from it, on success 91 // returning the base directly and the offsets indirectly using the Offsets 92 // argument 93 Value *decomposeGEP(Value *&Offsets, FixedVectorType *Ty, 94 GetElementPtrInst *GEP, IRBuilder<> &Builder); 95 // Compute the scale of this gather/scatter instruction 96 int computeScale(unsigned GEPElemSize, unsigned MemoryElemSize); 97 // If the value is a constant, or derived from constants via additions 98 // and multilications, return its numeric value 99 Optional<int64_t> getIfConst(const Value *V); 100 // If Inst is an add instruction, check whether one summand is a 101 // constant. If so, scale this constant and return it together with 102 // the other summand. 103 std::pair<Value *, int64_t> getVarAndConst(Value *Inst, int TypeScale); 104 105 Instruction *lowerGather(IntrinsicInst *I); 106 // Create a gather from a base + vector of offsets 107 Instruction *tryCreateMaskedGatherOffset(IntrinsicInst *I, Value *Ptr, 108 Instruction *&Root, 109 IRBuilder<> &Builder); 110 // Create a gather from a vector of pointers 111 Instruction *tryCreateMaskedGatherBase(IntrinsicInst *I, Value *Ptr, 112 IRBuilder<> &Builder, 113 int64_t Increment = 0); 114 // Create an incrementing gather from a vector of pointers 115 Instruction *tryCreateMaskedGatherBaseWB(IntrinsicInst *I, Value *Ptr, 116 IRBuilder<> &Builder, 117 int64_t Increment = 0); 118 119 Instruction *lowerScatter(IntrinsicInst *I); 120 // Create a scatter to a base + vector of offsets 121 Instruction *tryCreateMaskedScatterOffset(IntrinsicInst *I, Value *Offsets, 122 IRBuilder<> &Builder); 123 // Create a scatter to a vector of pointers 124 Instruction *tryCreateMaskedScatterBase(IntrinsicInst *I, Value *Ptr, 125 IRBuilder<> &Builder, 126 int64_t Increment = 0); 127 // Create an incrementing scatter from a vector of pointers 128 Instruction *tryCreateMaskedScatterBaseWB(IntrinsicInst *I, Value *Ptr, 129 IRBuilder<> &Builder, 130 int64_t Increment = 0); 131 132 // QI gathers and scatters can increment their offsets on their own if 133 // the increment is a constant value (digit) 134 Instruction *tryCreateIncrementingGatScat(IntrinsicInst *I, Value *Ptr, 135 IRBuilder<> &Builder); 136 // QI gathers/scatters can increment their offsets on their own if the 137 // increment is a constant value (digit) - this creates a writeback QI 138 // gather/scatter 139 Instruction *tryCreateIncrementingWBGatScat(IntrinsicInst *I, Value *BasePtr, 140 Value *Ptr, unsigned TypeScale, 141 IRBuilder<> &Builder); 142 143 // Optimise the base and offsets of the given address 144 bool optimiseAddress(Value *Address, BasicBlock *BB, LoopInfo *LI); 145 // Try to fold consecutive geps together into one 146 Value *foldGEP(GetElementPtrInst *GEP, Value *&Offsets, IRBuilder<> &Builder); 147 // Check whether these offsets could be moved out of the loop they're in 148 bool optimiseOffsets(Value *Offsets, BasicBlock *BB, LoopInfo *LI); 149 // Pushes the given add out of the loop 150 void pushOutAdd(PHINode *&Phi, Value *OffsSecondOperand, unsigned StartIndex); 151 // Pushes the given mul out of the loop 152 void pushOutMul(PHINode *&Phi, Value *IncrementPerRound, 153 Value *OffsSecondOperand, unsigned LoopIncrement, 154 IRBuilder<> &Builder); 155 }; 156 157 } // end anonymous namespace 158 159 char MVEGatherScatterLowering::ID = 0; 160 161 INITIALIZE_PASS(MVEGatherScatterLowering, DEBUG_TYPE, 162 "MVE gather/scattering lowering pass", false, false) 163 164 Pass *llvm::createMVEGatherScatterLoweringPass() { 165 return new MVEGatherScatterLowering(); 166 } 167 168 bool MVEGatherScatterLowering::isLegalTypeAndAlignment(unsigned NumElements, 169 unsigned ElemSize, 170 Align Alignment) { 171 if (((NumElements == 4 && 172 (ElemSize == 32 || ElemSize == 16 || ElemSize == 8)) || 173 (NumElements == 8 && (ElemSize == 16 || ElemSize == 8)) || 174 (NumElements == 16 && ElemSize == 8)) && 175 Alignment >= ElemSize / 8) 176 return true; 177 LLVM_DEBUG(dbgs() << "masked gathers/scatters: instruction does not have " 178 << "valid alignment or vector type \n"); 179 return false; 180 } 181 182 static bool checkOffsetSize(Value *Offsets, unsigned TargetElemCount) { 183 // Offsets that are not of type <N x i32> are sign extended by the 184 // getelementptr instruction, and MVE gathers/scatters treat the offset as 185 // unsigned. Thus, if the element size is smaller than 32, we can only allow 186 // positive offsets - i.e., the offsets are not allowed to be variables we 187 // can't look into. 188 // Additionally, <N x i32> offsets have to either originate from a zext of a 189 // vector with element types smaller or equal the type of the gather we're 190 // looking at, or consist of constants that we can check are small enough 191 // to fit into the gather type. 192 // Thus we check that 0 < value < 2^TargetElemSize. 193 unsigned TargetElemSize = 128 / TargetElemCount; 194 unsigned OffsetElemSize = cast<FixedVectorType>(Offsets->getType()) 195 ->getElementType() 196 ->getScalarSizeInBits(); 197 if (OffsetElemSize != TargetElemSize || OffsetElemSize != 32) { 198 Constant *ConstOff = dyn_cast<Constant>(Offsets); 199 if (!ConstOff) 200 return false; 201 int64_t TargetElemMaxSize = (1ULL << TargetElemSize); 202 auto CheckValueSize = [TargetElemMaxSize](Value *OffsetElem) { 203 ConstantInt *OConst = dyn_cast<ConstantInt>(OffsetElem); 204 if (!OConst) 205 return false; 206 int SExtValue = OConst->getSExtValue(); 207 if (SExtValue >= TargetElemMaxSize || SExtValue < 0) 208 return false; 209 return true; 210 }; 211 if (isa<FixedVectorType>(ConstOff->getType())) { 212 for (unsigned i = 0; i < TargetElemCount; i++) { 213 if (!CheckValueSize(ConstOff->getAggregateElement(i))) 214 return false; 215 } 216 } else { 217 if (!CheckValueSize(ConstOff)) 218 return false; 219 } 220 } 221 return true; 222 } 223 224 Value *MVEGatherScatterLowering::decomposePtr(Value *Ptr, Value *&Offsets, 225 int &Scale, FixedVectorType *Ty, 226 Type *MemoryTy, 227 IRBuilder<> &Builder) { 228 if (auto *GEP = dyn_cast<GetElementPtrInst>(Ptr)) { 229 if (Value *V = decomposeGEP(Offsets, Ty, GEP, Builder)) { 230 Scale = 231 computeScale(GEP->getSourceElementType()->getPrimitiveSizeInBits(), 232 MemoryTy->getScalarSizeInBits()); 233 return Scale == -1 ? nullptr : V; 234 } 235 } 236 237 // If we couldn't use the GEP (or it doesn't exist), attempt to use a 238 // BasePtr of 0 with Ptr as the Offsets, so long as there are only 4 239 // elements. 240 FixedVectorType *PtrTy = cast<FixedVectorType>(Ptr->getType()); 241 if (PtrTy->getNumElements() != 4 || MemoryTy->getScalarSizeInBits() == 32) 242 return nullptr; 243 Value *Zero = ConstantInt::get(Builder.getInt32Ty(), 0); 244 Value *BasePtr = Builder.CreateIntToPtr(Zero, Builder.getInt8PtrTy()); 245 Offsets = Builder.CreatePtrToInt( 246 Ptr, FixedVectorType::get(Builder.getInt32Ty(), 4)); 247 Scale = 0; 248 return BasePtr; 249 } 250 251 Value *MVEGatherScatterLowering::decomposeGEP(Value *&Offsets, 252 FixedVectorType *Ty, 253 GetElementPtrInst *GEP, 254 IRBuilder<> &Builder) { 255 if (!GEP) { 256 LLVM_DEBUG(dbgs() << "masked gathers/scatters: no getelementpointer " 257 << "found\n"); 258 return nullptr; 259 } 260 LLVM_DEBUG(dbgs() << "masked gathers/scatters: getelementpointer found." 261 << " Looking at intrinsic for base + vector of offsets\n"); 262 Value *GEPPtr = GEP->getPointerOperand(); 263 Offsets = GEP->getOperand(1); 264 if (GEPPtr->getType()->isVectorTy() || 265 !isa<FixedVectorType>(Offsets->getType())) 266 return nullptr; 267 268 if (GEP->getNumOperands() != 2) { 269 LLVM_DEBUG(dbgs() << "masked gathers/scatters: getelementptr with too many" 270 << " operands. Expanding.\n"); 271 return nullptr; 272 } 273 Offsets = GEP->getOperand(1); 274 unsigned OffsetsElemCount = 275 cast<FixedVectorType>(Offsets->getType())->getNumElements(); 276 // Paranoid check whether the number of parallel lanes is the same 277 assert(Ty->getNumElements() == OffsetsElemCount); 278 279 ZExtInst *ZextOffs = dyn_cast<ZExtInst>(Offsets); 280 if (ZextOffs) 281 Offsets = ZextOffs->getOperand(0); 282 FixedVectorType *OffsetType = cast<FixedVectorType>(Offsets->getType()); 283 284 // If the offsets are already being zext-ed to <N x i32>, that relieves us of 285 // having to make sure that they won't overflow. 286 if (!ZextOffs || cast<FixedVectorType>(ZextOffs->getDestTy()) 287 ->getElementType() 288 ->getScalarSizeInBits() != 32) 289 if (!checkOffsetSize(Offsets, OffsetsElemCount)) 290 return nullptr; 291 292 // The offset sizes have been checked; if any truncating or zext-ing is 293 // required to fix them, do that now 294 if (Ty != Offsets->getType()) { 295 if ((Ty->getElementType()->getScalarSizeInBits() < 296 OffsetType->getElementType()->getScalarSizeInBits())) { 297 Offsets = Builder.CreateTrunc(Offsets, Ty); 298 } else { 299 Offsets = Builder.CreateZExt(Offsets, VectorType::getInteger(Ty)); 300 } 301 } 302 // If none of the checks failed, return the gep's base pointer 303 LLVM_DEBUG(dbgs() << "masked gathers/scatters: found correct offsets\n"); 304 return GEPPtr; 305 } 306 307 void MVEGatherScatterLowering::lookThroughBitcast(Value *&Ptr) { 308 // Look through bitcast instruction if #elements is the same 309 if (auto *BitCast = dyn_cast<BitCastInst>(Ptr)) { 310 auto *BCTy = cast<FixedVectorType>(BitCast->getType()); 311 auto *BCSrcTy = cast<FixedVectorType>(BitCast->getOperand(0)->getType()); 312 if (BCTy->getNumElements() == BCSrcTy->getNumElements()) { 313 LLVM_DEBUG(dbgs() << "masked gathers/scatters: looking through " 314 << "bitcast\n"); 315 Ptr = BitCast->getOperand(0); 316 } 317 } 318 } 319 320 int MVEGatherScatterLowering::computeScale(unsigned GEPElemSize, 321 unsigned MemoryElemSize) { 322 // This can be a 32bit load/store scaled by 4, a 16bit load/store scaled by 2, 323 // or a 8bit, 16bit or 32bit load/store scaled by 1 324 if (GEPElemSize == 32 && MemoryElemSize == 32) 325 return 2; 326 else if (GEPElemSize == 16 && MemoryElemSize == 16) 327 return 1; 328 else if (GEPElemSize == 8) 329 return 0; 330 LLVM_DEBUG(dbgs() << "masked gathers/scatters: incorrect scale. Can't " 331 << "create intrinsic\n"); 332 return -1; 333 } 334 335 Optional<int64_t> MVEGatherScatterLowering::getIfConst(const Value *V) { 336 const Constant *C = dyn_cast<Constant>(V); 337 if (C != nullptr) 338 return Optional<int64_t>{C->getUniqueInteger().getSExtValue()}; 339 if (!isa<Instruction>(V)) 340 return Optional<int64_t>{}; 341 342 const Instruction *I = cast<Instruction>(V); 343 if (I->getOpcode() == Instruction::Add || 344 I->getOpcode() == Instruction::Mul) { 345 Optional<int64_t> Op0 = getIfConst(I->getOperand(0)); 346 Optional<int64_t> Op1 = getIfConst(I->getOperand(1)); 347 if (!Op0 || !Op1) 348 return Optional<int64_t>{}; 349 if (I->getOpcode() == Instruction::Add) 350 return Optional<int64_t>{Op0.getValue() + Op1.getValue()}; 351 if (I->getOpcode() == Instruction::Mul) 352 return Optional<int64_t>{Op0.getValue() * Op1.getValue()}; 353 } 354 return Optional<int64_t>{}; 355 } 356 357 std::pair<Value *, int64_t> 358 MVEGatherScatterLowering::getVarAndConst(Value *Inst, int TypeScale) { 359 std::pair<Value *, int64_t> ReturnFalse = 360 std::pair<Value *, int64_t>(nullptr, 0); 361 // At this point, the instruction we're looking at must be an add or we 362 // bail out 363 Instruction *Add = dyn_cast<Instruction>(Inst); 364 if (Add == nullptr || Add->getOpcode() != Instruction::Add) 365 return ReturnFalse; 366 367 Value *Summand; 368 Optional<int64_t> Const; 369 // Find out which operand the value that is increased is 370 if ((Const = getIfConst(Add->getOperand(0)))) 371 Summand = Add->getOperand(1); 372 else if ((Const = getIfConst(Add->getOperand(1)))) 373 Summand = Add->getOperand(0); 374 else 375 return ReturnFalse; 376 377 // Check that the constant is small enough for an incrementing gather 378 int64_t Immediate = Const.getValue() << TypeScale; 379 if (Immediate > 512 || Immediate < -512 || Immediate % 4 != 0) 380 return ReturnFalse; 381 382 return std::pair<Value *, int64_t>(Summand, Immediate); 383 } 384 385 Instruction *MVEGatherScatterLowering::lowerGather(IntrinsicInst *I) { 386 using namespace PatternMatch; 387 LLVM_DEBUG(dbgs() << "masked gathers: checking transform preconditions\n" 388 << *I << "\n"); 389 390 // @llvm.masked.gather.*(Ptrs, alignment, Mask, Src0) 391 // Attempt to turn the masked gather in I into a MVE intrinsic 392 // Potentially optimising the addressing modes as we do so. 393 auto *Ty = cast<FixedVectorType>(I->getType()); 394 Value *Ptr = I->getArgOperand(0); 395 Align Alignment = cast<ConstantInt>(I->getArgOperand(1))->getAlignValue(); 396 Value *Mask = I->getArgOperand(2); 397 Value *PassThru = I->getArgOperand(3); 398 399 if (!isLegalTypeAndAlignment(Ty->getNumElements(), Ty->getScalarSizeInBits(), 400 Alignment)) 401 return nullptr; 402 lookThroughBitcast(Ptr); 403 assert(Ptr->getType()->isVectorTy() && "Unexpected pointer type"); 404 405 IRBuilder<> Builder(I->getContext()); 406 Builder.SetInsertPoint(I); 407 Builder.SetCurrentDebugLocation(I->getDebugLoc()); 408 409 Instruction *Root = I; 410 411 Instruction *Load = tryCreateIncrementingGatScat(I, Ptr, Builder); 412 if (!Load) 413 Load = tryCreateMaskedGatherOffset(I, Ptr, Root, Builder); 414 if (!Load) 415 Load = tryCreateMaskedGatherBase(I, Ptr, Builder); 416 if (!Load) 417 return nullptr; 418 419 if (!isa<UndefValue>(PassThru) && !match(PassThru, m_Zero())) { 420 LLVM_DEBUG(dbgs() << "masked gathers: found non-trivial passthru - " 421 << "creating select\n"); 422 Load = SelectInst::Create(Mask, Load, PassThru); 423 Builder.Insert(Load); 424 } 425 426 Root->replaceAllUsesWith(Load); 427 Root->eraseFromParent(); 428 if (Root != I) 429 // If this was an extending gather, we need to get rid of the sext/zext 430 // sext/zext as well as of the gather itself 431 I->eraseFromParent(); 432 433 LLVM_DEBUG(dbgs() << "masked gathers: successfully built masked gather\n" 434 << *Load << "\n"); 435 return Load; 436 } 437 438 Instruction *MVEGatherScatterLowering::tryCreateMaskedGatherBase( 439 IntrinsicInst *I, Value *Ptr, IRBuilder<> &Builder, int64_t Increment) { 440 using namespace PatternMatch; 441 auto *Ty = cast<FixedVectorType>(I->getType()); 442 LLVM_DEBUG(dbgs() << "masked gathers: loading from vector of pointers\n"); 443 if (Ty->getNumElements() != 4 || Ty->getScalarSizeInBits() != 32) 444 // Can't build an intrinsic for this 445 return nullptr; 446 Value *Mask = I->getArgOperand(2); 447 if (match(Mask, m_One())) 448 return Builder.CreateIntrinsic(Intrinsic::arm_mve_vldr_gather_base, 449 {Ty, Ptr->getType()}, 450 {Ptr, Builder.getInt32(Increment)}); 451 else 452 return Builder.CreateIntrinsic( 453 Intrinsic::arm_mve_vldr_gather_base_predicated, 454 {Ty, Ptr->getType(), Mask->getType()}, 455 {Ptr, Builder.getInt32(Increment), Mask}); 456 } 457 458 Instruction *MVEGatherScatterLowering::tryCreateMaskedGatherBaseWB( 459 IntrinsicInst *I, Value *Ptr, IRBuilder<> &Builder, int64_t Increment) { 460 using namespace PatternMatch; 461 auto *Ty = cast<FixedVectorType>(I->getType()); 462 LLVM_DEBUG(dbgs() << "masked gathers: loading from vector of pointers with " 463 << "writeback\n"); 464 if (Ty->getNumElements() != 4 || Ty->getScalarSizeInBits() != 32) 465 // Can't build an intrinsic for this 466 return nullptr; 467 Value *Mask = I->getArgOperand(2); 468 if (match(Mask, m_One())) 469 return Builder.CreateIntrinsic(Intrinsic::arm_mve_vldr_gather_base_wb, 470 {Ty, Ptr->getType()}, 471 {Ptr, Builder.getInt32(Increment)}); 472 else 473 return Builder.CreateIntrinsic( 474 Intrinsic::arm_mve_vldr_gather_base_wb_predicated, 475 {Ty, Ptr->getType(), Mask->getType()}, 476 {Ptr, Builder.getInt32(Increment), Mask}); 477 } 478 479 Instruction *MVEGatherScatterLowering::tryCreateMaskedGatherOffset( 480 IntrinsicInst *I, Value *Ptr, Instruction *&Root, IRBuilder<> &Builder) { 481 using namespace PatternMatch; 482 483 Type *MemoryTy = I->getType(); 484 Type *ResultTy = MemoryTy; 485 486 unsigned Unsigned = 1; 487 // The size of the gather was already checked in isLegalTypeAndAlignment; 488 // if it was not a full vector width an appropriate extend should follow. 489 auto *Extend = Root; 490 if (MemoryTy->getPrimitiveSizeInBits() < 128) { 491 // Only transform gathers with exactly one use 492 if (!I->hasOneUse()) 493 return nullptr; 494 495 // The correct root to replace is not the CallInst itself, but the 496 // instruction which extends it 497 Extend = cast<Instruction>(*I->users().begin()); 498 if (isa<SExtInst>(Extend)) { 499 Unsigned = 0; 500 } else if (!isa<ZExtInst>(Extend)) { 501 LLVM_DEBUG(dbgs() << "masked gathers: extend needed but not provided. " 502 << "Expanding\n"); 503 return nullptr; 504 } 505 LLVM_DEBUG(dbgs() << "masked gathers: found an extending gather\n"); 506 ResultTy = Extend->getType(); 507 // The final size of the gather must be a full vector width 508 if (ResultTy->getPrimitiveSizeInBits() != 128) { 509 LLVM_DEBUG(dbgs() << "masked gathers: extending from the wrong type. " 510 << "Expanding\n"); 511 return nullptr; 512 } 513 } 514 515 Value *Offsets; 516 int Scale; 517 Value *BasePtr = decomposePtr( 518 Ptr, Offsets, Scale, cast<FixedVectorType>(ResultTy), MemoryTy, Builder); 519 if (!BasePtr) 520 return nullptr; 521 522 Root = Extend; 523 Value *Mask = I->getArgOperand(2); 524 if (!match(Mask, m_One())) 525 return Builder.CreateIntrinsic( 526 Intrinsic::arm_mve_vldr_gather_offset_predicated, 527 {ResultTy, BasePtr->getType(), Offsets->getType(), Mask->getType()}, 528 {BasePtr, Offsets, Builder.getInt32(MemoryTy->getScalarSizeInBits()), 529 Builder.getInt32(Scale), Builder.getInt32(Unsigned), Mask}); 530 else 531 return Builder.CreateIntrinsic( 532 Intrinsic::arm_mve_vldr_gather_offset, 533 {ResultTy, BasePtr->getType(), Offsets->getType()}, 534 {BasePtr, Offsets, Builder.getInt32(MemoryTy->getScalarSizeInBits()), 535 Builder.getInt32(Scale), Builder.getInt32(Unsigned)}); 536 } 537 538 Instruction *MVEGatherScatterLowering::lowerScatter(IntrinsicInst *I) { 539 using namespace PatternMatch; 540 LLVM_DEBUG(dbgs() << "masked scatters: checking transform preconditions\n" 541 << *I << "\n"); 542 543 // @llvm.masked.scatter.*(data, ptrs, alignment, mask) 544 // Attempt to turn the masked scatter in I into a MVE intrinsic 545 // Potentially optimising the addressing modes as we do so. 546 Value *Input = I->getArgOperand(0); 547 Value *Ptr = I->getArgOperand(1); 548 Align Alignment = cast<ConstantInt>(I->getArgOperand(2))->getAlignValue(); 549 auto *Ty = cast<FixedVectorType>(Input->getType()); 550 551 if (!isLegalTypeAndAlignment(Ty->getNumElements(), Ty->getScalarSizeInBits(), 552 Alignment)) 553 return nullptr; 554 555 lookThroughBitcast(Ptr); 556 assert(Ptr->getType()->isVectorTy() && "Unexpected pointer type"); 557 558 IRBuilder<> Builder(I->getContext()); 559 Builder.SetInsertPoint(I); 560 Builder.SetCurrentDebugLocation(I->getDebugLoc()); 561 562 Instruction *Store = tryCreateIncrementingGatScat(I, Ptr, Builder); 563 if (!Store) 564 Store = tryCreateMaskedScatterOffset(I, Ptr, Builder); 565 if (!Store) 566 Store = tryCreateMaskedScatterBase(I, Ptr, Builder); 567 if (!Store) 568 return nullptr; 569 570 LLVM_DEBUG(dbgs() << "masked scatters: successfully built masked scatter\n" 571 << *Store << "\n"); 572 I->eraseFromParent(); 573 return Store; 574 } 575 576 Instruction *MVEGatherScatterLowering::tryCreateMaskedScatterBase( 577 IntrinsicInst *I, Value *Ptr, IRBuilder<> &Builder, int64_t Increment) { 578 using namespace PatternMatch; 579 Value *Input = I->getArgOperand(0); 580 auto *Ty = cast<FixedVectorType>(Input->getType()); 581 // Only QR variants allow truncating 582 if (!(Ty->getNumElements() == 4 && Ty->getScalarSizeInBits() == 32)) { 583 // Can't build an intrinsic for this 584 return nullptr; 585 } 586 Value *Mask = I->getArgOperand(3); 587 // int_arm_mve_vstr_scatter_base(_predicated) addr, offset, data(, mask) 588 LLVM_DEBUG(dbgs() << "masked scatters: storing to a vector of pointers\n"); 589 if (match(Mask, m_One())) 590 return Builder.CreateIntrinsic(Intrinsic::arm_mve_vstr_scatter_base, 591 {Ptr->getType(), Input->getType()}, 592 {Ptr, Builder.getInt32(Increment), Input}); 593 else 594 return Builder.CreateIntrinsic( 595 Intrinsic::arm_mve_vstr_scatter_base_predicated, 596 {Ptr->getType(), Input->getType(), Mask->getType()}, 597 {Ptr, Builder.getInt32(Increment), Input, Mask}); 598 } 599 600 Instruction *MVEGatherScatterLowering::tryCreateMaskedScatterBaseWB( 601 IntrinsicInst *I, Value *Ptr, IRBuilder<> &Builder, int64_t Increment) { 602 using namespace PatternMatch; 603 Value *Input = I->getArgOperand(0); 604 auto *Ty = cast<FixedVectorType>(Input->getType()); 605 LLVM_DEBUG(dbgs() << "masked scatters: storing to a vector of pointers " 606 << "with writeback\n"); 607 if (Ty->getNumElements() != 4 || Ty->getScalarSizeInBits() != 32) 608 // Can't build an intrinsic for this 609 return nullptr; 610 Value *Mask = I->getArgOperand(3); 611 if (match(Mask, m_One())) 612 return Builder.CreateIntrinsic(Intrinsic::arm_mve_vstr_scatter_base_wb, 613 {Ptr->getType(), Input->getType()}, 614 {Ptr, Builder.getInt32(Increment), Input}); 615 else 616 return Builder.CreateIntrinsic( 617 Intrinsic::arm_mve_vstr_scatter_base_wb_predicated, 618 {Ptr->getType(), Input->getType(), Mask->getType()}, 619 {Ptr, Builder.getInt32(Increment), Input, Mask}); 620 } 621 622 Instruction *MVEGatherScatterLowering::tryCreateMaskedScatterOffset( 623 IntrinsicInst *I, Value *Ptr, IRBuilder<> &Builder) { 624 using namespace PatternMatch; 625 Value *Input = I->getArgOperand(0); 626 Value *Mask = I->getArgOperand(3); 627 Type *InputTy = Input->getType(); 628 Type *MemoryTy = InputTy; 629 630 LLVM_DEBUG(dbgs() << "masked scatters: getelementpointer found. Storing" 631 << " to base + vector of offsets\n"); 632 // If the input has been truncated, try to integrate that trunc into the 633 // scatter instruction (we don't care about alignment here) 634 if (TruncInst *Trunc = dyn_cast<TruncInst>(Input)) { 635 Value *PreTrunc = Trunc->getOperand(0); 636 Type *PreTruncTy = PreTrunc->getType(); 637 if (PreTruncTy->getPrimitiveSizeInBits() == 128) { 638 Input = PreTrunc; 639 InputTy = PreTruncTy; 640 } 641 } 642 bool ExtendInput = false; 643 if (InputTy->getPrimitiveSizeInBits() < 128 && 644 InputTy->isIntOrIntVectorTy()) { 645 // If we can't find a trunc to incorporate into the instruction, create an 646 // implicit one with a zext, so that we can still create a scatter. We know 647 // that the input type is 4x/8x/16x and of type i8/i16/i32, so any type 648 // smaller than 128 bits will divide evenly into a 128bit vector. 649 InputTy = InputTy->getWithNewBitWidth( 650 128 / cast<FixedVectorType>(InputTy)->getNumElements()); 651 ExtendInput = true; 652 LLVM_DEBUG(dbgs() << "masked scatters: Small input type, will extend:\n" 653 << *Input << "\n"); 654 } 655 if (InputTy->getPrimitiveSizeInBits() != 128) { 656 LLVM_DEBUG(dbgs() << "masked scatters: cannot create scatters for " 657 "non-standard input types. Expanding.\n"); 658 return nullptr; 659 } 660 661 Value *Offsets; 662 int Scale; 663 Value *BasePtr = decomposePtr( 664 Ptr, Offsets, Scale, cast<FixedVectorType>(InputTy), MemoryTy, Builder); 665 if (!BasePtr) 666 return nullptr; 667 668 if (ExtendInput) 669 Input = Builder.CreateZExt(Input, InputTy); 670 if (!match(Mask, m_One())) 671 return Builder.CreateIntrinsic( 672 Intrinsic::arm_mve_vstr_scatter_offset_predicated, 673 {BasePtr->getType(), Offsets->getType(), Input->getType(), 674 Mask->getType()}, 675 {BasePtr, Offsets, Input, 676 Builder.getInt32(MemoryTy->getScalarSizeInBits()), 677 Builder.getInt32(Scale), Mask}); 678 else 679 return Builder.CreateIntrinsic( 680 Intrinsic::arm_mve_vstr_scatter_offset, 681 {BasePtr->getType(), Offsets->getType(), Input->getType()}, 682 {BasePtr, Offsets, Input, 683 Builder.getInt32(MemoryTy->getScalarSizeInBits()), 684 Builder.getInt32(Scale)}); 685 } 686 687 Instruction *MVEGatherScatterLowering::tryCreateIncrementingGatScat( 688 IntrinsicInst *I, Value *Ptr, IRBuilder<> &Builder) { 689 FixedVectorType *Ty; 690 if (I->getIntrinsicID() == Intrinsic::masked_gather) 691 Ty = cast<FixedVectorType>(I->getType()); 692 else 693 Ty = cast<FixedVectorType>(I->getArgOperand(0)->getType()); 694 695 // Incrementing gathers only exist for v4i32 696 if (Ty->getNumElements() != 4 || Ty->getScalarSizeInBits() != 32) 697 return nullptr; 698 // Incrementing gathers are not beneficial outside of a loop 699 Loop *L = LI->getLoopFor(I->getParent()); 700 if (L == nullptr) 701 return nullptr; 702 703 // Decompose the GEP into Base and Offsets 704 GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(Ptr); 705 Value *Offsets; 706 Value *BasePtr = decomposeGEP(Offsets, Ty, GEP, Builder); 707 if (!BasePtr) 708 return nullptr; 709 710 LLVM_DEBUG(dbgs() << "masked gathers/scatters: trying to build incrementing " 711 "wb gather/scatter\n"); 712 713 // The gep was in charge of making sure the offsets are scaled correctly 714 // - calculate that factor so it can be applied by hand 715 DataLayout DT = I->getParent()->getParent()->getParent()->getDataLayout(); 716 int TypeScale = 717 computeScale(DT.getTypeSizeInBits(GEP->getOperand(0)->getType()), 718 DT.getTypeSizeInBits(GEP->getType()) / 719 cast<FixedVectorType>(GEP->getType())->getNumElements()); 720 if (TypeScale == -1) 721 return nullptr; 722 723 if (GEP->hasOneUse()) { 724 // Only in this case do we want to build a wb gather, because the wb will 725 // change the phi which does affect other users of the gep (which will still 726 // be using the phi in the old way) 727 if (auto *Load = tryCreateIncrementingWBGatScat(I, BasePtr, Offsets, 728 TypeScale, Builder)) 729 return Load; 730 } 731 732 LLVM_DEBUG(dbgs() << "masked gathers/scatters: trying to build incrementing " 733 "non-wb gather/scatter\n"); 734 735 std::pair<Value *, int64_t> Add = getVarAndConst(Offsets, TypeScale); 736 if (Add.first == nullptr) 737 return nullptr; 738 Value *OffsetsIncoming = Add.first; 739 int64_t Immediate = Add.second; 740 741 // Make sure the offsets are scaled correctly 742 Instruction *ScaledOffsets = BinaryOperator::Create( 743 Instruction::Shl, OffsetsIncoming, 744 Builder.CreateVectorSplat(Ty->getNumElements(), Builder.getInt32(TypeScale)), 745 "ScaledIndex", I); 746 // Add the base to the offsets 747 OffsetsIncoming = BinaryOperator::Create( 748 Instruction::Add, ScaledOffsets, 749 Builder.CreateVectorSplat( 750 Ty->getNumElements(), 751 Builder.CreatePtrToInt( 752 BasePtr, 753 cast<VectorType>(ScaledOffsets->getType())->getElementType())), 754 "StartIndex", I); 755 756 if (I->getIntrinsicID() == Intrinsic::masked_gather) 757 return tryCreateMaskedGatherBase(I, OffsetsIncoming, Builder, Immediate); 758 else 759 return tryCreateMaskedScatterBase(I, OffsetsIncoming, Builder, Immediate); 760 } 761 762 Instruction *MVEGatherScatterLowering::tryCreateIncrementingWBGatScat( 763 IntrinsicInst *I, Value *BasePtr, Value *Offsets, unsigned TypeScale, 764 IRBuilder<> &Builder) { 765 // Check whether this gather's offset is incremented by a constant - if so, 766 // and the load is of the right type, we can merge this into a QI gather 767 Loop *L = LI->getLoopFor(I->getParent()); 768 // Offsets that are worth merging into this instruction will be incremented 769 // by a constant, thus we're looking for an add of a phi and a constant 770 PHINode *Phi = dyn_cast<PHINode>(Offsets); 771 if (Phi == nullptr || Phi->getNumIncomingValues() != 2 || 772 Phi->getParent() != L->getHeader() || Phi->getNumUses() != 2) 773 // No phi means no IV to write back to; if there is a phi, we expect it 774 // to have exactly two incoming values; the only phis we are interested in 775 // will be loop IV's and have exactly two uses, one in their increment and 776 // one in the gather's gep 777 return nullptr; 778 779 unsigned IncrementIndex = 780 Phi->getIncomingBlock(0) == L->getLoopLatch() ? 0 : 1; 781 // Look through the phi to the phi increment 782 Offsets = Phi->getIncomingValue(IncrementIndex); 783 784 std::pair<Value *, int64_t> Add = getVarAndConst(Offsets, TypeScale); 785 if (Add.first == nullptr) 786 return nullptr; 787 Value *OffsetsIncoming = Add.first; 788 int64_t Immediate = Add.second; 789 if (OffsetsIncoming != Phi) 790 // Then the increment we are looking at is not an increment of the 791 // induction variable, and we don't want to do a writeback 792 return nullptr; 793 794 Builder.SetInsertPoint(&Phi->getIncomingBlock(1 - IncrementIndex)->back()); 795 unsigned NumElems = 796 cast<FixedVectorType>(OffsetsIncoming->getType())->getNumElements(); 797 798 // Make sure the offsets are scaled correctly 799 Instruction *ScaledOffsets = BinaryOperator::Create( 800 Instruction::Shl, Phi->getIncomingValue(1 - IncrementIndex), 801 Builder.CreateVectorSplat(NumElems, Builder.getInt32(TypeScale)), 802 "ScaledIndex", &Phi->getIncomingBlock(1 - IncrementIndex)->back()); 803 // Add the base to the offsets 804 OffsetsIncoming = BinaryOperator::Create( 805 Instruction::Add, ScaledOffsets, 806 Builder.CreateVectorSplat( 807 NumElems, 808 Builder.CreatePtrToInt( 809 BasePtr, 810 cast<VectorType>(ScaledOffsets->getType())->getElementType())), 811 "StartIndex", &Phi->getIncomingBlock(1 - IncrementIndex)->back()); 812 // The gather is pre-incrementing 813 OffsetsIncoming = BinaryOperator::Create( 814 Instruction::Sub, OffsetsIncoming, 815 Builder.CreateVectorSplat(NumElems, Builder.getInt32(Immediate)), 816 "PreIncrementStartIndex", 817 &Phi->getIncomingBlock(1 - IncrementIndex)->back()); 818 Phi->setIncomingValue(1 - IncrementIndex, OffsetsIncoming); 819 820 Builder.SetInsertPoint(I); 821 822 Instruction *EndResult; 823 Instruction *NewInduction; 824 if (I->getIntrinsicID() == Intrinsic::masked_gather) { 825 // Build the incrementing gather 826 Value *Load = tryCreateMaskedGatherBaseWB(I, Phi, Builder, Immediate); 827 // One value to be handed to whoever uses the gather, one is the loop 828 // increment 829 EndResult = ExtractValueInst::Create(Load, 0, "Gather"); 830 NewInduction = ExtractValueInst::Create(Load, 1, "GatherIncrement"); 831 Builder.Insert(EndResult); 832 Builder.Insert(NewInduction); 833 } else { 834 // Build the incrementing scatter 835 EndResult = NewInduction = 836 tryCreateMaskedScatterBaseWB(I, Phi, Builder, Immediate); 837 } 838 Instruction *AddInst = cast<Instruction>(Offsets); 839 AddInst->replaceAllUsesWith(NewInduction); 840 AddInst->eraseFromParent(); 841 Phi->setIncomingValue(IncrementIndex, NewInduction); 842 843 return EndResult; 844 } 845 846 void MVEGatherScatterLowering::pushOutAdd(PHINode *&Phi, 847 Value *OffsSecondOperand, 848 unsigned StartIndex) { 849 LLVM_DEBUG(dbgs() << "masked gathers/scatters: optimising add instruction\n"); 850 Instruction *InsertionPoint = 851 &cast<Instruction>(Phi->getIncomingBlock(StartIndex)->back()); 852 // Initialize the phi with a vector that contains a sum of the constants 853 Instruction *NewIndex = BinaryOperator::Create( 854 Instruction::Add, Phi->getIncomingValue(StartIndex), OffsSecondOperand, 855 "PushedOutAdd", InsertionPoint); 856 unsigned IncrementIndex = StartIndex == 0 ? 1 : 0; 857 858 // Order such that start index comes first (this reduces mov's) 859 Phi->addIncoming(NewIndex, Phi->getIncomingBlock(StartIndex)); 860 Phi->addIncoming(Phi->getIncomingValue(IncrementIndex), 861 Phi->getIncomingBlock(IncrementIndex)); 862 Phi->removeIncomingValue(IncrementIndex); 863 Phi->removeIncomingValue(StartIndex); 864 } 865 866 void MVEGatherScatterLowering::pushOutMul(PHINode *&Phi, 867 Value *IncrementPerRound, 868 Value *OffsSecondOperand, 869 unsigned LoopIncrement, 870 IRBuilder<> &Builder) { 871 LLVM_DEBUG(dbgs() << "masked gathers/scatters: optimising mul instruction\n"); 872 873 // Create a new scalar add outside of the loop and transform it to a splat 874 // by which loop variable can be incremented 875 Instruction *InsertionPoint = &cast<Instruction>( 876 Phi->getIncomingBlock(LoopIncrement == 1 ? 0 : 1)->back()); 877 878 // Create a new index 879 Value *StartIndex = BinaryOperator::Create( 880 Instruction::Mul, Phi->getIncomingValue(LoopIncrement == 1 ? 0 : 1), 881 OffsSecondOperand, "PushedOutMul", InsertionPoint); 882 883 Instruction *Product = 884 BinaryOperator::Create(Instruction::Mul, IncrementPerRound, 885 OffsSecondOperand, "Product", InsertionPoint); 886 // Increment NewIndex by Product instead of the multiplication 887 Instruction *NewIncrement = BinaryOperator::Create( 888 Instruction::Add, Phi, Product, "IncrementPushedOutMul", 889 cast<Instruction>(Phi->getIncomingBlock(LoopIncrement)->back()) 890 .getPrevNode()); 891 892 Phi->addIncoming(StartIndex, 893 Phi->getIncomingBlock(LoopIncrement == 1 ? 0 : 1)); 894 Phi->addIncoming(NewIncrement, Phi->getIncomingBlock(LoopIncrement)); 895 Phi->removeIncomingValue((unsigned)0); 896 Phi->removeIncomingValue((unsigned)0); 897 } 898 899 // Check whether all usages of this instruction are as offsets of 900 // gathers/scatters or simple arithmetics only used by gathers/scatters 901 static bool hasAllGatScatUsers(Instruction *I) { 902 if (I->hasNUses(0)) { 903 return false; 904 } 905 bool Gatscat = true; 906 for (User *U : I->users()) { 907 if (!isa<Instruction>(U)) 908 return false; 909 if (isa<GetElementPtrInst>(U) || 910 isGatherScatter(dyn_cast<IntrinsicInst>(U))) { 911 return Gatscat; 912 } else { 913 unsigned OpCode = cast<Instruction>(U)->getOpcode(); 914 if ((OpCode == Instruction::Add || OpCode == Instruction::Mul) && 915 hasAllGatScatUsers(cast<Instruction>(U))) { 916 continue; 917 } 918 return false; 919 } 920 } 921 return Gatscat; 922 } 923 924 bool MVEGatherScatterLowering::optimiseOffsets(Value *Offsets, BasicBlock *BB, 925 LoopInfo *LI) { 926 LLVM_DEBUG(dbgs() << "masked gathers/scatters: trying to optimize\n" 927 << *Offsets << "\n"); 928 // Optimise the addresses of gathers/scatters by moving invariant 929 // calculations out of the loop 930 if (!isa<Instruction>(Offsets)) 931 return false; 932 Instruction *Offs = cast<Instruction>(Offsets); 933 if (Offs->getOpcode() != Instruction::Add && 934 Offs->getOpcode() != Instruction::Mul) 935 return false; 936 Loop *L = LI->getLoopFor(BB); 937 if (L == nullptr) 938 return false; 939 if (!Offs->hasOneUse()) { 940 if (!hasAllGatScatUsers(Offs)) 941 return false; 942 } 943 944 // Find out which, if any, operand of the instruction 945 // is a phi node 946 PHINode *Phi; 947 int OffsSecondOp; 948 if (isa<PHINode>(Offs->getOperand(0))) { 949 Phi = cast<PHINode>(Offs->getOperand(0)); 950 OffsSecondOp = 1; 951 } else if (isa<PHINode>(Offs->getOperand(1))) { 952 Phi = cast<PHINode>(Offs->getOperand(1)); 953 OffsSecondOp = 0; 954 } else { 955 bool Changed = true; 956 if (isa<Instruction>(Offs->getOperand(0)) && 957 L->contains(cast<Instruction>(Offs->getOperand(0)))) 958 Changed |= optimiseOffsets(Offs->getOperand(0), BB, LI); 959 if (isa<Instruction>(Offs->getOperand(1)) && 960 L->contains(cast<Instruction>(Offs->getOperand(1)))) 961 Changed |= optimiseOffsets(Offs->getOperand(1), BB, LI); 962 if (!Changed) { 963 return false; 964 } else { 965 if (isa<PHINode>(Offs->getOperand(0))) { 966 Phi = cast<PHINode>(Offs->getOperand(0)); 967 OffsSecondOp = 1; 968 } else if (isa<PHINode>(Offs->getOperand(1))) { 969 Phi = cast<PHINode>(Offs->getOperand(1)); 970 OffsSecondOp = 0; 971 } else { 972 return false; 973 } 974 } 975 } 976 // A phi node we want to perform this function on should be from the 977 // loop header, and shouldn't have more than 2 incoming values 978 if (Phi->getParent() != L->getHeader() || 979 Phi->getNumIncomingValues() != 2) 980 return false; 981 982 // The phi must be an induction variable 983 int IncrementingBlock = -1; 984 985 for (int i = 0; i < 2; i++) 986 if (auto *Op = dyn_cast<Instruction>(Phi->getIncomingValue(i))) 987 if (Op->getOpcode() == Instruction::Add && 988 (Op->getOperand(0) == Phi || Op->getOperand(1) == Phi)) 989 IncrementingBlock = i; 990 if (IncrementingBlock == -1) 991 return false; 992 993 Instruction *IncInstruction = 994 cast<Instruction>(Phi->getIncomingValue(IncrementingBlock)); 995 996 // If the phi is not used by anything else, we can just adapt it when 997 // replacing the instruction; if it is, we'll have to duplicate it 998 PHINode *NewPhi; 999 Value *IncrementPerRound = IncInstruction->getOperand( 1000 (IncInstruction->getOperand(0) == Phi) ? 1 : 0); 1001 1002 // Get the value that is added to/multiplied with the phi 1003 Value *OffsSecondOperand = Offs->getOperand(OffsSecondOp); 1004 1005 if (IncrementPerRound->getType() != OffsSecondOperand->getType() || 1006 !L->isLoopInvariant(OffsSecondOperand)) 1007 // Something has gone wrong, abort 1008 return false; 1009 1010 // Only proceed if the increment per round is a constant or an instruction 1011 // which does not originate from within the loop 1012 if (!isa<Constant>(IncrementPerRound) && 1013 !(isa<Instruction>(IncrementPerRound) && 1014 !L->contains(cast<Instruction>(IncrementPerRound)))) 1015 return false; 1016 1017 if (Phi->getNumUses() == 2) { 1018 // No other users -> reuse existing phi (One user is the instruction 1019 // we're looking at, the other is the phi increment) 1020 if (IncInstruction->getNumUses() != 1) { 1021 // If the incrementing instruction does have more users than 1022 // our phi, we need to copy it 1023 IncInstruction = BinaryOperator::Create( 1024 Instruction::BinaryOps(IncInstruction->getOpcode()), Phi, 1025 IncrementPerRound, "LoopIncrement", IncInstruction); 1026 Phi->setIncomingValue(IncrementingBlock, IncInstruction); 1027 } 1028 NewPhi = Phi; 1029 } else { 1030 // There are other users -> create a new phi 1031 NewPhi = PHINode::Create(Phi->getType(), 0, "NewPhi", Phi); 1032 std::vector<Value *> Increases; 1033 // Copy the incoming values of the old phi 1034 NewPhi->addIncoming(Phi->getIncomingValue(IncrementingBlock == 1 ? 0 : 1), 1035 Phi->getIncomingBlock(IncrementingBlock == 1 ? 0 : 1)); 1036 IncInstruction = BinaryOperator::Create( 1037 Instruction::BinaryOps(IncInstruction->getOpcode()), NewPhi, 1038 IncrementPerRound, "LoopIncrement", IncInstruction); 1039 NewPhi->addIncoming(IncInstruction, 1040 Phi->getIncomingBlock(IncrementingBlock)); 1041 IncrementingBlock = 1; 1042 } 1043 1044 IRBuilder<> Builder(BB->getContext()); 1045 Builder.SetInsertPoint(Phi); 1046 Builder.SetCurrentDebugLocation(Offs->getDebugLoc()); 1047 1048 switch (Offs->getOpcode()) { 1049 case Instruction::Add: 1050 pushOutAdd(NewPhi, OffsSecondOperand, IncrementingBlock == 1 ? 0 : 1); 1051 break; 1052 case Instruction::Mul: 1053 pushOutMul(NewPhi, IncrementPerRound, OffsSecondOperand, IncrementingBlock, 1054 Builder); 1055 break; 1056 default: 1057 return false; 1058 } 1059 LLVM_DEBUG(dbgs() << "masked gathers/scatters: simplified loop variable " 1060 << "add/mul\n"); 1061 1062 // The instruction has now been "absorbed" into the phi value 1063 Offs->replaceAllUsesWith(NewPhi); 1064 if (Offs->hasNUses(0)) 1065 Offs->eraseFromParent(); 1066 // Clean up the old increment in case it's unused because we built a new 1067 // one 1068 if (IncInstruction->hasNUses(0)) 1069 IncInstruction->eraseFromParent(); 1070 1071 return true; 1072 } 1073 1074 static Value *CheckAndCreateOffsetAdd(Value *X, Value *Y, Value *GEP, 1075 IRBuilder<> &Builder) { 1076 // Splat the non-vector value to a vector of the given type - if the value is 1077 // a constant (and its value isn't too big), we can even use this opportunity 1078 // to scale it to the size of the vector elements 1079 auto FixSummands = [&Builder](FixedVectorType *&VT, Value *&NonVectorVal) { 1080 ConstantInt *Const; 1081 if ((Const = dyn_cast<ConstantInt>(NonVectorVal)) && 1082 VT->getElementType() != NonVectorVal->getType()) { 1083 unsigned TargetElemSize = VT->getElementType()->getPrimitiveSizeInBits(); 1084 uint64_t N = Const->getZExtValue(); 1085 if (N < (unsigned)(1 << (TargetElemSize - 1))) { 1086 NonVectorVal = Builder.CreateVectorSplat( 1087 VT->getNumElements(), Builder.getIntN(TargetElemSize, N)); 1088 return; 1089 } 1090 } 1091 NonVectorVal = 1092 Builder.CreateVectorSplat(VT->getNumElements(), NonVectorVal); 1093 }; 1094 1095 FixedVectorType *XElType = dyn_cast<FixedVectorType>(X->getType()); 1096 FixedVectorType *YElType = dyn_cast<FixedVectorType>(Y->getType()); 1097 // If one of X, Y is not a vector, we have to splat it in order 1098 // to add the two of them. 1099 if (XElType && !YElType) { 1100 FixSummands(XElType, Y); 1101 YElType = cast<FixedVectorType>(Y->getType()); 1102 } else if (YElType && !XElType) { 1103 FixSummands(YElType, X); 1104 XElType = cast<FixedVectorType>(X->getType()); 1105 } 1106 assert(XElType && YElType && "Unknown vector types"); 1107 // Check that the summands are of compatible types 1108 if (XElType != YElType) { 1109 LLVM_DEBUG(dbgs() << "masked gathers/scatters: incompatible gep offsets\n"); 1110 return nullptr; 1111 } 1112 1113 if (XElType->getElementType()->getScalarSizeInBits() != 32) { 1114 // Check that by adding the vectors we do not accidentally 1115 // create an overflow 1116 Constant *ConstX = dyn_cast<Constant>(X); 1117 Constant *ConstY = dyn_cast<Constant>(Y); 1118 if (!ConstX || !ConstY) 1119 return nullptr; 1120 unsigned TargetElemSize = 128 / XElType->getNumElements(); 1121 for (unsigned i = 0; i < XElType->getNumElements(); i++) { 1122 ConstantInt *ConstXEl = 1123 dyn_cast<ConstantInt>(ConstX->getAggregateElement(i)); 1124 ConstantInt *ConstYEl = 1125 dyn_cast<ConstantInt>(ConstY->getAggregateElement(i)); 1126 if (!ConstXEl || !ConstYEl || 1127 ConstXEl->getZExtValue() + ConstYEl->getZExtValue() >= 1128 (unsigned)(1 << (TargetElemSize - 1))) 1129 return nullptr; 1130 } 1131 } 1132 1133 Value *Add = Builder.CreateAdd(X, Y); 1134 1135 FixedVectorType *GEPType = cast<FixedVectorType>(GEP->getType()); 1136 if (checkOffsetSize(Add, GEPType->getNumElements())) 1137 return Add; 1138 else 1139 return nullptr; 1140 } 1141 1142 Value *MVEGatherScatterLowering::foldGEP(GetElementPtrInst *GEP, 1143 Value *&Offsets, 1144 IRBuilder<> &Builder) { 1145 Value *GEPPtr = GEP->getPointerOperand(); 1146 Offsets = GEP->getOperand(1); 1147 // We only merge geps with constant offsets, because only for those 1148 // we can make sure that we do not cause an overflow 1149 if (!isa<Constant>(Offsets)) 1150 return nullptr; 1151 GetElementPtrInst *BaseGEP; 1152 if ((BaseGEP = dyn_cast<GetElementPtrInst>(GEPPtr))) { 1153 // Merge the two geps into one 1154 Value *BaseBasePtr = foldGEP(BaseGEP, Offsets, Builder); 1155 if (!BaseBasePtr) 1156 return nullptr; 1157 Offsets = 1158 CheckAndCreateOffsetAdd(Offsets, GEP->getOperand(1), GEP, Builder); 1159 if (Offsets == nullptr) 1160 return nullptr; 1161 return BaseBasePtr; 1162 } 1163 return GEPPtr; 1164 } 1165 1166 bool MVEGatherScatterLowering::optimiseAddress(Value *Address, BasicBlock *BB, 1167 LoopInfo *LI) { 1168 GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(Address); 1169 if (!GEP) 1170 return false; 1171 bool Changed = false; 1172 if (GEP->hasOneUse() && 1173 dyn_cast<GetElementPtrInst>(GEP->getPointerOperand())) { 1174 IRBuilder<> Builder(GEP->getContext()); 1175 Builder.SetInsertPoint(GEP); 1176 Builder.SetCurrentDebugLocation(GEP->getDebugLoc()); 1177 Value *Offsets; 1178 Value *Base = foldGEP(GEP, Offsets, Builder); 1179 // We only want to merge the geps if there is a real chance that they can be 1180 // used by an MVE gather; thus the offset has to have the correct size 1181 // (always i32 if it is not of vector type) and the base has to be a 1182 // pointer. 1183 if (Offsets && Base && Base != GEP) { 1184 GetElementPtrInst *NewAddress = GetElementPtrInst::Create( 1185 GEP->getSourceElementType(), Base, Offsets, "gep.merged", GEP); 1186 GEP->replaceAllUsesWith(NewAddress); 1187 GEP = NewAddress; 1188 Changed = true; 1189 } 1190 } 1191 Changed |= optimiseOffsets(GEP->getOperand(1), GEP->getParent(), LI); 1192 return Changed; 1193 } 1194 1195 bool MVEGatherScatterLowering::runOnFunction(Function &F) { 1196 if (!EnableMaskedGatherScatters) 1197 return false; 1198 auto &TPC = getAnalysis<TargetPassConfig>(); 1199 auto &TM = TPC.getTM<TargetMachine>(); 1200 auto *ST = &TM.getSubtarget<ARMSubtarget>(F); 1201 if (!ST->hasMVEIntegerOps()) 1202 return false; 1203 LI = &getAnalysis<LoopInfoWrapperPass>().getLoopInfo(); 1204 SmallVector<IntrinsicInst *, 4> Gathers; 1205 SmallVector<IntrinsicInst *, 4> Scatters; 1206 1207 bool Changed = false; 1208 1209 for (BasicBlock &BB : F) { 1210 Changed |= SimplifyInstructionsInBlock(&BB); 1211 1212 for (Instruction &I : BB) { 1213 IntrinsicInst *II = dyn_cast<IntrinsicInst>(&I); 1214 if (II && II->getIntrinsicID() == Intrinsic::masked_gather && 1215 isa<FixedVectorType>(II->getType())) { 1216 Gathers.push_back(II); 1217 Changed |= optimiseAddress(II->getArgOperand(0), II->getParent(), LI); 1218 } else if (II && II->getIntrinsicID() == Intrinsic::masked_scatter && 1219 isa<FixedVectorType>(II->getArgOperand(0)->getType())) { 1220 Scatters.push_back(II); 1221 Changed |= optimiseAddress(II->getArgOperand(1), II->getParent(), LI); 1222 } 1223 } 1224 } 1225 for (unsigned i = 0; i < Gathers.size(); i++) { 1226 IntrinsicInst *I = Gathers[i]; 1227 Instruction *L = lowerGather(I); 1228 if (L == nullptr) 1229 continue; 1230 1231 // Get rid of any now dead instructions 1232 SimplifyInstructionsInBlock(L->getParent()); 1233 Changed = true; 1234 } 1235 1236 for (unsigned i = 0; i < Scatters.size(); i++) { 1237 IntrinsicInst *I = Scatters[i]; 1238 Instruction *S = lowerScatter(I); 1239 if (S == nullptr) 1240 continue; 1241 1242 // Get rid of any now dead instructions 1243 SimplifyInstructionsInBlock(S->getParent()); 1244 Changed = true; 1245 } 1246 return Changed; 1247 } 1248