1 //===- Legality.cpp -------------------------------------------------------===// 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 "llvm/Transforms/Vectorize/SandboxVectorizer/Legality.h" 10 #include "llvm/SandboxIR/Instruction.h" 11 #include "llvm/SandboxIR/Operator.h" 12 #include "llvm/SandboxIR/Utils.h" 13 #include "llvm/SandboxIR/Value.h" 14 #include "llvm/Support/Debug.h" 15 #include "llvm/Transforms/Vectorize/SandboxVectorizer/VecUtils.h" 16 17 namespace llvm::sandboxir { 18 19 #define DEBUG_TYPE "SBVec:Legality" 20 21 #ifndef NDEBUG 22 void LegalityResult::dump() const { 23 print(dbgs()); 24 dbgs() << "\n"; 25 } 26 #endif // NDEBUG 27 28 std::optional<ResultReason> 29 LegalityAnalysis::notVectorizableBasedOnOpcodesAndTypes( 30 ArrayRef<Value *> Bndl) { 31 auto *I0 = cast<Instruction>(Bndl[0]); 32 auto Opcode = I0->getOpcode(); 33 // If they have different opcodes, then we cannot form a vector (for now). 34 if (any_of(drop_begin(Bndl), [Opcode](Value *V) { 35 return cast<Instruction>(V)->getOpcode() != Opcode; 36 })) 37 return ResultReason::DiffOpcodes; 38 39 // If not the same scalar type, Pack. This will accept scalars and vectors as 40 // long as the element type is the same. 41 Type *ElmTy0 = VecUtils::getElementType(Utils::getExpectedType(I0)); 42 if (any_of(drop_begin(Bndl), [ElmTy0](Value *V) { 43 return VecUtils::getElementType(Utils::getExpectedType(V)) != ElmTy0; 44 })) 45 return ResultReason::DiffTypes; 46 47 // TODO: Allow vectorization of instrs with different flags as long as we 48 // change them to the least common one. 49 // For now pack if differnt FastMathFlags. 50 if (isa<FPMathOperator>(I0)) { 51 FastMathFlags FMF0 = cast<Instruction>(Bndl[0])->getFastMathFlags(); 52 if (any_of(drop_begin(Bndl), [FMF0](auto *V) { 53 return cast<Instruction>(V)->getFastMathFlags() != FMF0; 54 })) 55 return ResultReason::DiffMathFlags; 56 } 57 58 // TODO: Allow vectorization by using common flags. 59 // For now Pack if they don't have the same wrap flags. 60 bool CanHaveWrapFlags = 61 isa<OverflowingBinaryOperator>(I0) || isa<TruncInst>(I0); 62 if (CanHaveWrapFlags) { 63 bool NUW0 = I0->hasNoUnsignedWrap(); 64 bool NSW0 = I0->hasNoSignedWrap(); 65 if (any_of(drop_begin(Bndl), [NUW0, NSW0](auto *V) { 66 return cast<Instruction>(V)->hasNoUnsignedWrap() != NUW0 || 67 cast<Instruction>(V)->hasNoSignedWrap() != NSW0; 68 })) { 69 return ResultReason::DiffWrapFlags; 70 } 71 } 72 73 // Now we need to do further checks for specific opcodes. 74 switch (Opcode) { 75 case Instruction::Opcode::ZExt: 76 case Instruction::Opcode::SExt: 77 case Instruction::Opcode::FPToUI: 78 case Instruction::Opcode::FPToSI: 79 case Instruction::Opcode::FPExt: 80 case Instruction::Opcode::PtrToInt: 81 case Instruction::Opcode::IntToPtr: 82 case Instruction::Opcode::SIToFP: 83 case Instruction::Opcode::UIToFP: 84 case Instruction::Opcode::Trunc: 85 case Instruction::Opcode::FPTrunc: 86 case Instruction::Opcode::BitCast: { 87 // We have already checked that they are of the same opcode. 88 assert(all_of(Bndl, 89 [Opcode](Value *V) { 90 return cast<Instruction>(V)->getOpcode() == Opcode; 91 }) && 92 "Different opcodes, should have early returned!"); 93 // But for these opcodes we should also check the operand type. 94 Type *FromTy0 = Utils::getExpectedType(I0->getOperand(0)); 95 if (any_of(drop_begin(Bndl), [FromTy0](Value *V) { 96 return Utils::getExpectedType(cast<User>(V)->getOperand(0)) != 97 FromTy0; 98 })) 99 return ResultReason::DiffTypes; 100 return std::nullopt; 101 } 102 case Instruction::Opcode::FCmp: 103 case Instruction::Opcode::ICmp: { 104 // We need the same predicate.. 105 auto Pred0 = cast<CmpInst>(I0)->getPredicate(); 106 bool Same = all_of(Bndl, [Pred0](Value *V) { 107 return cast<CmpInst>(V)->getPredicate() == Pred0; 108 }); 109 if (Same) 110 return std::nullopt; 111 return ResultReason::DiffOpcodes; 112 } 113 case Instruction::Opcode::Select: 114 case Instruction::Opcode::FNeg: 115 case Instruction::Opcode::Add: 116 case Instruction::Opcode::FAdd: 117 case Instruction::Opcode::Sub: 118 case Instruction::Opcode::FSub: 119 case Instruction::Opcode::Mul: 120 case Instruction::Opcode::FMul: 121 case Instruction::Opcode::FRem: 122 case Instruction::Opcode::UDiv: 123 case Instruction::Opcode::SDiv: 124 case Instruction::Opcode::FDiv: 125 case Instruction::Opcode::URem: 126 case Instruction::Opcode::SRem: 127 case Instruction::Opcode::Shl: 128 case Instruction::Opcode::LShr: 129 case Instruction::Opcode::AShr: 130 case Instruction::Opcode::And: 131 case Instruction::Opcode::Or: 132 case Instruction::Opcode::Xor: 133 return std::nullopt; 134 case Instruction::Opcode::Load: 135 if (VecUtils::areConsecutive<LoadInst>(Bndl, SE, DL)) 136 return std::nullopt; 137 return ResultReason::NotConsecutive; 138 case Instruction::Opcode::Store: 139 if (VecUtils::areConsecutive<StoreInst>(Bndl, SE, DL)) 140 return std::nullopt; 141 return ResultReason::NotConsecutive; 142 case Instruction::Opcode::PHI: 143 return ResultReason::Unimplemented; 144 case Instruction::Opcode::Opaque: 145 return ResultReason::Unimplemented; 146 case Instruction::Opcode::Br: 147 case Instruction::Opcode::Ret: 148 case Instruction::Opcode::AddrSpaceCast: 149 case Instruction::Opcode::InsertElement: 150 case Instruction::Opcode::InsertValue: 151 case Instruction::Opcode::ExtractElement: 152 case Instruction::Opcode::ExtractValue: 153 case Instruction::Opcode::ShuffleVector: 154 case Instruction::Opcode::Call: 155 case Instruction::Opcode::GetElementPtr: 156 case Instruction::Opcode::Switch: 157 return ResultReason::Unimplemented; 158 case Instruction::Opcode::VAArg: 159 case Instruction::Opcode::Freeze: 160 case Instruction::Opcode::Fence: 161 case Instruction::Opcode::Invoke: 162 case Instruction::Opcode::CallBr: 163 case Instruction::Opcode::LandingPad: 164 case Instruction::Opcode::CatchPad: 165 case Instruction::Opcode::CleanupPad: 166 case Instruction::Opcode::CatchRet: 167 case Instruction::Opcode::CleanupRet: 168 case Instruction::Opcode::Resume: 169 case Instruction::Opcode::CatchSwitch: 170 case Instruction::Opcode::AtomicRMW: 171 case Instruction::Opcode::AtomicCmpXchg: 172 case Instruction::Opcode::Alloca: 173 case Instruction::Opcode::Unreachable: 174 return ResultReason::Infeasible; 175 } 176 177 return std::nullopt; 178 } 179 180 #ifndef NDEBUG 181 static void dumpBndl(ArrayRef<Value *> Bndl) { 182 for (auto *V : Bndl) 183 dbgs() << *V << "\n"; 184 } 185 #endif // NDEBUG 186 187 const LegalityResult &LegalityAnalysis::canVectorize(ArrayRef<Value *> Bndl, 188 bool SkipScheduling) { 189 // If Bndl contains values other than instructions, we need to Pack. 190 if (any_of(Bndl, [](auto *V) { return !isa<Instruction>(V); })) { 191 LLVM_DEBUG(dbgs() << "Not vectorizing: Not Instructions:\n"; 192 dumpBndl(Bndl);); 193 return createLegalityResult<Pack>(ResultReason::NotInstructions); 194 } 195 196 if (auto ReasonOpt = notVectorizableBasedOnOpcodesAndTypes(Bndl)) 197 return createLegalityResult<Pack>(*ReasonOpt); 198 199 // TODO: Check for existing vectors containing values in Bndl. 200 201 if (!SkipScheduling) { 202 // TODO: Try to remove the IBndl vector. 203 SmallVector<Instruction *, 8> IBndl; 204 IBndl.reserve(Bndl.size()); 205 for (auto *V : Bndl) 206 IBndl.push_back(cast<Instruction>(V)); 207 if (!Sched.trySchedule(IBndl)) 208 return createLegalityResult<Pack>(ResultReason::CantSchedule); 209 } 210 211 return createLegalityResult<Widen>(); 212 } 213 } // namespace llvm::sandboxir 214