================
@@ -233,23 +233,64 @@ static bool isSMEABIRoutineCall(const CallInst &CI,
SMEAttrs(F->getName(),
TLI.getRuntimeLibcallsInfo()).isSMEABIRoutine();
}
+static bool isPossiblyIncompatibleIntrinsic(const Instruction *I,
+ bool ConsiderZA, bool ConsiderSM) {
+ auto *II = dyn_cast<IntrinsicInst>(I);
+ if (!II)
+ return false;
+
+ StringRef Name = II->getCalledFunction()->getName();
+ if (ConsiderZA && Name.starts_with("llvm.aarch64.sme."))
+ return true;
+
+ if (ConsiderSM) {
+ if (Name.starts_with("llvm.aarch64.neon") ||
+ Name.starts_with("llvm.aarch64.sve") ||
+ Name.starts_with("llvm.aarch64.sme") ||
+ Name.starts_with("llvm.vscale") ||
+ Name.starts_with("llvm.masked.gather") ||
+ Name.starts_with("llvm.masked.scatter")) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
/// Returns true if the function has explicit operations that can only be
/// lowered using incompatible instructions for the selected mode. This also
/// returns true if the function F may use or modify ZA state.
static bool hasPossibleIncompatibleOps(const Function *F,
- const AArch64TargetLowering &TLI) {
+ const AArch64TargetLowering &TLI,
+ bool ConsiderZA, bool ConsiderSM) {
+ assert((ConsiderZA || ConsiderSM) && "No SME state to consider");
for (const BasicBlock &BB : *F) {
for (const Instruction &I : BB) {
- // Be conservative for now and assume that any call to inline asm or to
- // intrinsics could could result in non-streaming ops (e.g. calls to
- // @llvm.aarch64.* or @llvm.gather/scatter intrinsics). We can assume
that
- // all native LLVM instructions can be lowered to compatible
instructions.
- if (isa<CallInst>(I) && !I.isDebugOrPseudoInst() &&
- (cast<CallInst>(I).isInlineAsm() || isa<IntrinsicInst>(I) ||
- isSMEABIRoutineCall(cast<CallInst>(I), TLI)))
+ // We can assume that all native LLVM instructions can be lowered to
+ // compatible instructions.
+ if (!isa<CallInst>(I) || I.isDebugOrPseudoInst())
+ continue;
+ // Be conservative for now and assume that any call to inline asm could
+ // result in different behaviour.
+ if (cast<CallInst>(I).isInlineAsm())
+ return true;
+
+ // Be conservative around operations on scalable types, as those may have
+ // different behaviour in/out of streaming mode.
+ if (ConsiderSM && (I.getType()->isScalableTy() ||
+ any_of(I.operand_values(), [](const Value *V) {
+ return V->getType()->isScalableTy();
+ })))
+ return true;
----------------
MacDue wrote:
What about simply returning `vector.vscale`? If we allow inlining scalable
types, we should also inlining checking `vscale`. Note: We currently cave this
case out (though if this check was removed, not all ways to compute it).
I don't think it's correct from an LLVM IR perspective to allow this. Though I
understand "streaming mode" somewhat breaks LLVM's model of vscale, so this
area is somewhat under defined, which is not a great basis for optimizations.
Note: The implicit effect of this would be to allow auto-vectorization within
streaming functions, as a non-streaming function could be vectorized and then
later inlined.
https://github.com/llvm/llvm-project/pull/223393
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits