[Polly] Reject scalable vector types (#177871)

Polly currently does not consider types without fixed length, which can
be encountered if an input source uses e.g. ARM SVE builtins. Such
programs have already been optimized manually. Non-fixed type lengths
also add to the difficulty of dependency analysis. Skip such types
entirely for now.
 
Fixes: #177859
This commit is contained in:
Michael Kruse 2026-01-25 21:08:45 +01:00 committed by GitHub
parent 14bdd06fba
commit e5d235831d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 176 additions and 0 deletions

View File

@ -401,6 +401,10 @@ private:
/// @param Context The context of scop detection.
bool isValidMemoryAccess(MemAccInst Inst, DetectionContext &Context) const;
/// Filter out types that we do not support.
bool isCompatibleType(Instruction *Inst, llvm::Type *Ty,
DetectionContext &Context);
/// Check if an instruction can be part of a Scop.
///
/// @param Inst The instruction to check.

View File

@ -31,6 +31,7 @@ class BasicBlock;
class OptimizationRemarkEmitter;
class Region;
class SCEV;
class Type;
} // namespace llvm
namespace polly {
@ -96,6 +97,7 @@ enum class RejectReasonKind {
FuncCall,
NonSimpleMemoryAccess,
IncompatibleType,
Alias,
@ -885,6 +887,32 @@ public:
std::string getEndUserMessage() const override;
//@}
};
//===----------------------------------------------------------------------===//
/// Captures types that Polly does not support
class ReportIncompatibleType final : public RejectReason {
// The offending call instruction.
Instruction *Inst;
llvm::Type *Ty;
public:
ReportIncompatibleType(Instruction *Inst, llvm::Type *Ty);
/// @name LLVM-RTTI interface
//@{
static bool classof(const RejectReason *RR);
//@}
/// @name RejectReason interface
//@{
std::string getRemarkName() const override;
const BasicBlock *getRemarkBB() const override;
std::string getMessage() const override;
const DebugLoc &getDebugLoc() const override;
std::string getEndUserMessage() const override;
//@}
};
} // namespace polly
#endif // POLLY_SCOPDETECTIONDIAGNOSTIC_H

View File

@ -1204,6 +1204,17 @@ bool ScopDetection::isValidMemoryAccess(MemAccInst Inst,
return isValidAccess(Inst, AccessFunction, BasePointer, Context);
}
bool ScopDetection::isCompatibleType(Instruction *Inst, Type *Ty,
DetectionContext &Context) {
if (!Ty)
return false;
if (isa<ScalableVectorType>(Ty))
return invalid<ReportIncompatibleType>(Context, /*Assert=*/true, Inst, Ty);
return true;
}
bool ScopDetection::isValidInstruction(Instruction &Inst,
DetectionContext &Context) {
for (auto &Op : Inst.operands()) {
@ -1212,6 +1223,9 @@ bool ScopDetection::isValidInstruction(Instruction &Inst,
if (!OpInst)
continue;
if (!isCompatibleType(&Inst, Op->getType(), Context))
return false;
if (isErrorBlock(*OpInst->getParent(), Context.CurRegion)) {
auto *PHI = dyn_cast<PHINode>(OpInst);
if (PHI) {
@ -1229,6 +1243,9 @@ bool ScopDetection::isValidInstruction(Instruction &Inst,
if (isa<LandingPadInst>(&Inst) || isa<ResumeInst>(&Inst))
return false;
if (!isCompatibleType(&Inst, Inst.getType(), Context))
return false;
// We only check the call instruction but not invoke instruction.
if (CallInst *CI = dyn_cast<CallInst>(&Inst)) {
if (isValidCallInst(*CI, Context))

View File

@ -72,6 +72,7 @@ static Statistic RejectStatistics[] = {
SCOP_STAT(FuncCall, "Function call with side effects"),
SCOP_STAT(NonSimpleMemoryAccess,
"Complicated access semantics (volatile or atomic)"),
SCOP_STAT(IncompatibleType, "Non-fixed size type (e.g. Scalable vector)"),
SCOP_STAT(Alias, "Base address aliasing"),
SCOP_STAT(Other, ""),
SCOP_STAT(IntToPtr, "Integer to pointer conversions"),
@ -841,4 +842,35 @@ const DebugLoc &ReportUnprofitable::getDebugLoc() const {
bool ReportUnprofitable::classof(const RejectReason *RR) {
return RR->getKind() == RejectReasonKind::Unprofitable;
}
//===----------------------------------------------------------------------===//
// ReportIncompatibleType
ReportIncompatibleType::ReportIncompatibleType(Instruction *Inst, Type *Ty)
: RejectReason(RejectReasonKind::IncompatibleType), Inst(Inst), Ty(Ty) {}
std::string ReportIncompatibleType::getRemarkName() const {
return "IncompatibleType";
}
const BasicBlock *ReportIncompatibleType::getRemarkBB() const {
return Inst->getParent();
}
std::string ReportIncompatibleType::getMessage() const {
return "Incompatible type: " + *Inst;
}
const DebugLoc &ReportIncompatibleType::getDebugLoc() const {
return Inst->getDebugLoc();
}
std::string ReportIncompatibleType::getEndUserMessage() const {
return "Incompatible (non-fixed size) type: " + *Ty;
}
bool ReportIncompatibleType::classof(const RejectReason *RR) {
return RR->getKind() == RejectReasonKind::IncompatibleType;
}
} // namespace polly

View File

@ -0,0 +1,95 @@
; RUN: opt %loadNPMPolly '-passes=polly-custom<detect>' -pass-remarks-missed=polly-detect -disable-output < %s 2>&1 | FileCheck %s
; CHECK: remark: /app/example.c:73:19: The following errors keep this region from being a Scop.
; CHECK: remark: /app/example.c:73:19: Incompatible (non-fixed size) type: <vscale x 8 x half>
; CHECK: remark: /app/example.c:73:19: Invalid Scop candidate ends here.
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32"
target triple = "aarch64"
define void @sve(i32 %n, ptr noalias nonnull %A) {
entry:
br label %for
for:
%j = phi i32 [ 0, %entry ], [ %j.inc, %inc ]
%j.cmp = icmp slt i32 %j, %n
br i1 %j.cmp, label %body, label %exit
body:
%ld = load <vscale x 8 x half>, ptr %A, align 16, !dbg !38, !tbaa !53
#dbg_value(<vscale x 8 x half> %ld, !46, !DIExpression(), !55)
br label %inc
inc:
%j.inc = add nuw nsw i32 %j, 1
br label %for
exit:
br label %return
return:
ret void
}
!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!27, !28, !29, !30, !31, !32}
!llvm.ident = !{!33}
!llvm.errno.tbaa = !{!34}
!0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "clang version 23.0.0git (/home/meinersbur/src/llvm/main/_src/clang dcb6e15a83c907be0e71e01f3509d530135c56ae)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, retainedTypes: !2, globals: !9, splitDebugInlining: false, nameTableKind: None)
!1 = !DIFile(filename: "../issue177859.c", directory: "/home/meinersbur/src/llvm/main/release", checksumkind: CSK_MD5, checksum: "cabf91caf1d9144496f767cef582f50d")
!2 = !{!3, !6}
!3 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !4, size: 64)
!4 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !5)
!5 = !DIBasicType(name: "__fp16", size: 16, encoding: DW_ATE_float)
!6 = !DIDerivedType(tag: DW_TAG_typedef, name: "ggml_float", file: !7, line: 48, baseType: !8)
!7 = !DIFile(filename: "/app/example.c", directory: "")
!8 = !DIBasicType(name: "double", size: 64, encoding: DW_ATE_float)
!9 = !{!10, !16, !21}
!10 = !DIGlobalVariableExpression(var: !11, expr: !DIExpression())
!11 = distinct !DIGlobalVariable(scope: null, file: !7, line: 51, type: !12, isLocal: true, isDefinition: true)
!12 = !DICompositeType(tag: DW_TAG_array_type, baseType: !13, size: 72, elements: !14)
!13 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_unsigned_char)
!14 = !{!15}
!15 = !DISubrange(count: 9)
!16 = !DIGlobalVariableExpression(var: !17, expr: !DIExpression())
!17 = distinct !DIGlobalVariable(scope: null, file: !7, line: 51, type: !18, isLocal: true, isDefinition: true)
!18 = !DICompositeType(tag: DW_TAG_array_type, baseType: !13, size: 120, elements: !19)
!19 = !{!20}
!20 = !DISubrange(count: 15)
!21 = !DIGlobalVariableExpression(var: !22, expr: !DIExpression())
!22 = distinct !DIGlobalVariable(scope: null, file: !7, line: 51, type: !23, isLocal: true, isDefinition: true)
!23 = !DICompositeType(tag: DW_TAG_array_type, baseType: !24, size: 952, elements: !25)
!24 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !13)
!25 = !{!26}
!26 = !DISubrange(count: 119)
!27 = !{i32 7, !"Dwarf Version", i32 5}
!28 = !{i32 2, !"Debug Info Version", i32 3}
!29 = !{i32 1, !"wchar_size", i32 4}
!30 = !{i32 7, !"uwtable", i32 2}
!31 = !{i32 7, !"frame-pointer", i32 4}
!32 = !{i32 7, !"debug-info-assignment-tracking", i1 true}
!33 = !{!"clang version 23.0.0git (/home/meinersbur/src/llvm/main/_src/clang dcb6e15a83c907be0e71e01f3509d530135c56ae)"}
!34 = !{!35, !35, i64 0}
!35 = !{!"int", !36, i64 0}
!36 = !{!"omnipotent char", !37, i64 0}
!37 = !{!"Simple C/C++ TBAA"}
!38 = !DILocation(line: 73, column: 19, scope: !39, atomGroup: 74, atomRank: 2)
!39 = distinct !DILexicalBlock(scope: !40, file: !7, line: 71, column: 53)
!40 = distinct !DILexicalBlock(scope: !41, file: !7, line: 71, column: 9)
!41 = distinct !DILexicalBlock(scope: !42, file: !7, line: 71, column: 9)
!42 = distinct !DISubprogram(name: "ggml_vec_dot_f16", scope: !7, file: !7, line: 50, type: !43, scopeLine: 50, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !45, keyInstructions: true)
!43 = !DISubroutineType(types: !44)
!44 = !{null}
!45 = !{!46}
!46 = !DILocalVariable(name: "ay1", scope: !42, file: !7, line: 70, type: !47)
!47 = !DIDerivedType(tag: DW_TAG_typedef, name: "svfloat16_t", file: !48, line: 36, baseType: !49)
!48 = !DIFile(filename: "/cefs/9b/9b63fa585dbaa73402339c99_clang-trunk-20260125/lib/clang/23/include/arm_sve.h", directory: "")
!49 = !DIDerivedType(tag: DW_TAG_typedef, name: "__SVFloat16_t", file: !1, baseType: !50)
!50 = !DICompositeType(tag: DW_TAG_array_type, baseType: !5, flags: DIFlagVector, elements: !51)
!51 = !{!52}
!52 = !DISubrange(lowerBound: 0, upperBound: !DIExpression(DW_OP_constu, 4, DW_OP_bregx, 46, 0, DW_OP_mul, DW_OP_constu, 1, DW_OP_minus))
!53 = !{!54, !54, i64 0}
!54 = !{!"__fp16", !36, i64 0}
!55 = !DILocation(line: 0, scope: !42)