18
18
#include " llvm/ADT/Statistic.h"
19
19
#include " llvm/Analysis/ValueTracking.h"
20
20
#include " llvm/CodeGen/TargetPassConfig.h"
21
+ #include " llvm/IR/Dominators.h"
21
22
#include " llvm/IR/IRBuilder.h"
22
23
#include " llvm/IR/InstVisitor.h"
23
24
#include " llvm/IR/Intrinsics.h"
25
+ #include " llvm/IR/IntrinsicsRISCV.h"
24
26
#include " llvm/IR/PatternMatch.h"
25
27
#include " llvm/InitializePasses.h"
26
28
#include " llvm/Pass.h"
@@ -35,6 +37,7 @@ namespace {
35
37
class RISCVCodeGenPrepare : public FunctionPass ,
36
38
public InstVisitor<RISCVCodeGenPrepare, bool > {
37
39
const DataLayout *DL;
40
+ const DominatorTree *DT;
38
41
const RISCVSubtarget *ST;
39
42
40
43
public:
@@ -48,12 +51,14 @@ class RISCVCodeGenPrepare : public FunctionPass,
48
51
49
52
void getAnalysisUsage (AnalysisUsage &AU) const override {
50
53
AU.setPreservesCFG ();
54
+ AU.addRequired <DominatorTreeWrapperPass>();
51
55
AU.addRequired <TargetPassConfig>();
52
56
}
53
57
54
58
bool visitInstruction (Instruction &I) { return false ; }
55
59
bool visitAnd (BinaryOperator &BO);
56
60
bool visitIntrinsicInst (IntrinsicInst &I);
61
+ bool expandVPStrideLoad (IntrinsicInst &I);
57
62
};
58
63
59
64
} // end anonymous namespace
@@ -128,6 +133,9 @@ bool RISCVCodeGenPrepare::visitAnd(BinaryOperator &BO) {
128
133
// Which eliminates the scalar -> vector -> scalar crossing during instruction
129
134
// selection.
130
135
bool RISCVCodeGenPrepare::visitIntrinsicInst (IntrinsicInst &I) {
136
+ if (expandVPStrideLoad (I))
137
+ return true ;
138
+
131
139
if (I.getIntrinsicID () != Intrinsic::vector_reduce_fadd)
132
140
return false ;
133
141
@@ -155,6 +163,47 @@ bool RISCVCodeGenPrepare::visitIntrinsicInst(IntrinsicInst &I) {
155
163
return true ;
156
164
}
157
165
166
+ bool RISCVCodeGenPrepare::expandVPStrideLoad (IntrinsicInst &II) {
167
+ if (ST->hasOptimizedZeroStrideLoad ())
168
+ return false ;
169
+
170
+ Value *BasePtr, *VL;
171
+ using namespace PatternMatch ;
172
+ if (!match (&II, m_Intrinsic<Intrinsic::experimental_vp_strided_load>(
173
+ m_Value (BasePtr), m_Zero (), m_AllOnes (), m_Value (VL))))
174
+ return false ;
175
+
176
+ if (!isKnownNonZero (VL, {*DL, DT, nullptr , &II}))
177
+ return false ;
178
+
179
+ auto *VTy = cast<VectorType>(II.getType ());
180
+
181
+ IRBuilder<> Builder (&II);
182
+
183
+ // Extend VL from i32 to XLen if needed.
184
+ if (ST->is64Bit ())
185
+ VL = Builder.CreateZExt (VL, Builder.getInt64Ty ());
186
+
187
+ Type *STy = VTy->getElementType ();
188
+ Value *Val = Builder.CreateLoad (STy, BasePtr);
189
+ const auto &TLI = *ST->getTargetLowering ();
190
+ Value *Res;
191
+
192
+ // TODO: Also support fixed/illegal vector types to splat with evl = vl.
193
+ if (isa<ScalableVectorType>(VTy) && TLI.isTypeLegal (EVT::getEVT (VTy))) {
194
+ unsigned VMVOp = STy->isFloatingPointTy () ? Intrinsic::riscv_vfmv_v_f
195
+ : Intrinsic::riscv_vmv_v_x;
196
+ Res = Builder.CreateIntrinsic (VMVOp, {VTy, VL->getType ()},
197
+ {PoisonValue::get (VTy), Val, VL});
198
+ } else {
199
+ Res = Builder.CreateVectorSplat (VTy->getElementCount (), Val);
200
+ }
201
+
202
+ II.replaceAllUsesWith (Res);
203
+ II.eraseFromParent ();
204
+ return true ;
205
+ }
206
+
158
207
bool RISCVCodeGenPrepare::runOnFunction (Function &F) {
159
208
if (skipFunction (F))
160
209
return false ;
@@ -164,6 +213,7 @@ bool RISCVCodeGenPrepare::runOnFunction(Function &F) {
164
213
ST = &TM.getSubtarget <RISCVSubtarget>(F);
165
214
166
215
DL = &F.getDataLayout ();
216
+ DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree ();
167
217
168
218
bool MadeChange = false ;
169
219
for (auto &BB : F)
0 commit comments