================
@@ -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:
I think the regular inliner checks should be conservative and avoid inlining
that changes behavior or could be very costly (e.g. inlining a loop with fixed
vectors into a streaming function). If the function is marked `alwaysinline` we
should allow more cases (e.g., inlining fixed vectors), but I'm still not
convinced on the correctness of behavior changing cases (I don't really think
we have this case clearly defined).
https://github.com/llvm/llvm-project/pull/223393
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits