Skip to content

Commit ac5fe90

Browse files
[Clang][SME] Refactor checkArmStreamingBuiltin.
Rather than filtering the calling function's features the PR splits the builtin guard into distinct non-streaming and streaming guards that are compared to the active features in full. This has no affect on the current builtin definitions[1] but will allow us in the future to reference SVE features within streaming builtin guards and SME features within non-streaming builtin guards. [1] The change uncovered an issue whereby a couple of builtins where tagged with VerifyRuntimeMode but did not include both streaming and non-streaming guards. Some of those builtins are available in SME2p1 but to keep the PR mostly NFC I've ensured they are only available in non-streaming mode, thus matching the existing implementation.
1 parent 222e795 commit ac5fe90

File tree

3 files changed

+47
-39
lines changed

3 files changed

+47
-39
lines changed

clang/include/clang/Basic/arm_sve.td

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -264,22 +264,22 @@ let SVETargetGuard = "sve,bf16", SMETargetGuard = "sme,bf16" in {
264264
def SVLD1RQ_BF : SInst<"svld1rq[_{2}]", "dPc", "b", MergeNone, "aarch64_sve_ld1rq", [VerifyRuntimeMode]>;
265265
}
266266

267-
multiclass StructLoad<string name, string proto, string i> {
268-
def : SInst<name, proto, "csilUcUsUiUlhfdm", MergeNone, i, [IsStructLoad, VerifyRuntimeMode]>;
267+
multiclass StructLoad<string name, string proto, string i, list<FlagType> f = []> {
268+
def : SInst<name, proto, "csilUcUsUiUlhfdm", MergeNone, i, !listconcat(f, [IsStructLoad])>;
269269
let SVETargetGuard = "sve,bf16", SMETargetGuard = "sme,bf16" in {
270-
def: SInst<name, proto, "b", MergeNone, i, [IsStructLoad, VerifyRuntimeMode]>;
270+
def: SInst<name, proto, "b", MergeNone, i, !listconcat(f, [IsStructLoad])>;
271271
}
272272
}
273273

274274
// Load N-element structure into N vectors (scalar base)
275-
defm SVLD2 : StructLoad<"svld2[_{2}]", "2Pc", "aarch64_sve_ld2_sret">;
276-
defm SVLD3 : StructLoad<"svld3[_{2}]", "3Pc", "aarch64_sve_ld3_sret">;
277-
defm SVLD4 : StructLoad<"svld4[_{2}]", "4Pc", "aarch64_sve_ld4_sret">;
275+
defm SVLD2 : StructLoad<"svld2[_{2}]", "2Pc", "aarch64_sve_ld2_sret", [VerifyRuntimeMode]>;
276+
defm SVLD3 : StructLoad<"svld3[_{2}]", "3Pc", "aarch64_sve_ld3_sret", [VerifyRuntimeMode]>;
277+
defm SVLD4 : StructLoad<"svld4[_{2}]", "4Pc", "aarch64_sve_ld4_sret", [VerifyRuntimeMode]>;
278278

279279
// Load N-element structure into N vectors (scalar base, VL displacement)
280-
defm SVLD2_VNUM : StructLoad<"svld2_vnum[_{2}]", "2Pcl", "aarch64_sve_ld2_sret">;
281-
defm SVLD3_VNUM : StructLoad<"svld3_vnum[_{2}]", "3Pcl", "aarch64_sve_ld3_sret">;
282-
defm SVLD4_VNUM : StructLoad<"svld4_vnum[_{2}]", "4Pcl", "aarch64_sve_ld4_sret">;
280+
defm SVLD2_VNUM : StructLoad<"svld2_vnum[_{2}]", "2Pcl", "aarch64_sve_ld2_sret", [VerifyRuntimeMode]>;
281+
defm SVLD3_VNUM : StructLoad<"svld3_vnum[_{2}]", "3Pcl", "aarch64_sve_ld3_sret", [VerifyRuntimeMode]>;
282+
defm SVLD4_VNUM : StructLoad<"svld4_vnum[_{2}]", "4Pcl", "aarch64_sve_ld4_sret", [VerifyRuntimeMode]>;
283283

284284
// Load one octoword and replicate (scalar base)
285285
let SVETargetGuard = "sve,f64mm", SMETargetGuard = InvalidMode in {
@@ -434,21 +434,21 @@ def SVST1H_SCATTER_INDEX_S : MInst<"svst1h_scatter[_{2}base]_index[_{d}]", "v
434434
def SVST1W_SCATTER_INDEX_S : MInst<"svst1w_scatter[_{2}base]_index[_{d}]", "vPuld", "lUl", [IsScatterStore], MemEltTyInt32, "aarch64_sve_st1_scatter_scalar_offset">;
435435
} // let SVETargetGuard = "sve"
436436

437-
multiclass StructStore<string name, string proto, string i> {
438-
def : SInst<name, proto, "csilUcUsUiUlhfdm", MergeNone, i, [IsStructStore, VerifyRuntimeMode]>;
437+
multiclass StructStore<string name, string proto, string i, list<FlagType> f = []> {
438+
def : SInst<name, proto, "csilUcUsUiUlhfdm", MergeNone, i, !listconcat(f, [IsStructStore])>;
439439
let SVETargetGuard = "sve,bf16", SMETargetGuard = "sme,bf16" in {
440-
def: SInst<name, proto, "b", MergeNone, i, [IsStructStore, VerifyRuntimeMode]>;
440+
def: SInst<name, proto, "b", MergeNone, i, !listconcat(f, [IsStructStore])>;
441441
}
442442
}
443443
// Store N vectors into N-element structure (scalar base)
444-
defm SVST2 : StructStore<"svst2[_{d}]", "vPp2", "aarch64_sve_st2">;
445-
defm SVST3 : StructStore<"svst3[_{d}]", "vPp3", "aarch64_sve_st3">;
446-
defm SVST4 : StructStore<"svst4[_{d}]", "vPp4", "aarch64_sve_st4">;
444+
defm SVST2 : StructStore<"svst2[_{d}]", "vPp2", "aarch64_sve_st2", [VerifyRuntimeMode]>;
445+
defm SVST3 : StructStore<"svst3[_{d}]", "vPp3", "aarch64_sve_st3", [VerifyRuntimeMode]>;
446+
defm SVST4 : StructStore<"svst4[_{d}]", "vPp4", "aarch64_sve_st4", [VerifyRuntimeMode]>;
447447

448448
// Store N vectors into N-element structure (scalar base, VL displacement)
449-
defm SVST2_VNUM : StructStore<"svst2_vnum[_{d}]", "vPpl2", "aarch64_sve_st2">;
450-
defm SVST3_VNUM : StructStore<"svst3_vnum[_{d}]", "vPpl3", "aarch64_sve_st3">;
451-
defm SVST4_VNUM : StructStore<"svst4_vnum[_{d}]", "vPpl4", "aarch64_sve_st4">;
449+
defm SVST2_VNUM : StructStore<"svst2_vnum[_{d}]", "vPpl2", "aarch64_sve_st2", [VerifyRuntimeMode]>;
450+
defm SVST3_VNUM : StructStore<"svst3_vnum[_{d}]", "vPpl3", "aarch64_sve_st3", [VerifyRuntimeMode]>;
451+
defm SVST4_VNUM : StructStore<"svst4_vnum[_{d}]", "vPpl4", "aarch64_sve_st4", [VerifyRuntimeMode]>;
452452

453453
// Store one vector, with no truncation, non-temporal (scalar base)
454454
def SVSTNT1 : MInst<"svstnt1[_{d}]", "vPpd", "csilUcUsUiUlhfdm", [IsStore, VerifyRuntimeMode], MemEltTyDefault, "aarch64_sve_stnt1">;

clang/lib/Sema/SemaARM.cpp

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -569,34 +569,39 @@ static bool checkArmStreamingBuiltin(Sema &S, CallExpr *TheCall,
569569
// * When compiling for SVE only, the caller must be in non-streaming mode.
570570
// * When compiling for both SVE and SME, the caller can be in either mode.
571571
if (BuiltinType == SemaARM::VerifyRuntimeMode) {
572-
llvm::StringMap<bool> CallerFeatureMapWithoutSVE;
573-
S.Context.getFunctionFeatureMap(CallerFeatureMapWithoutSVE, FD);
574-
CallerFeatureMapWithoutSVE["sve"] = false;
572+
llvm::StringMap<bool> CallerFeatures;
573+
S.Context.getFunctionFeatureMap(CallerFeatures, FD);
575574

576575
// Avoid emitting diagnostics for a function that can never compile.
577-
if (FnType == SemaARM::ArmStreaming && !CallerFeatureMapWithoutSVE["sme"])
576+
if (FnType == SemaARM::ArmStreaming && !CallerFeatures["sme"])
578577
return false;
579578

580-
llvm::StringMap<bool> CallerFeatureMapWithoutSME;
581-
S.Context.getFunctionFeatureMap(CallerFeatureMapWithoutSME, FD);
582-
CallerFeatureMapWithoutSME["sme"] = false;
579+
const auto FindTopLevelPipe = [](const char *S) {
580+
unsigned Depth = 0;
581+
unsigned I = 0, E = strlen(S);
582+
for (; I < E; ++I) {
583+
if (S[I] == '|' && Depth == 0)
584+
break;
585+
if (S[I] == '(')
586+
++Depth;
587+
else if (S[I] == ')')
588+
--Depth;
589+
}
590+
return I;
591+
};
592+
593+
const char *RequiredFeatures =
594+
S.Context.BuiltinInfo.getRequiredFeatures(BuiltinID);
595+
unsigned PipeIdx = FindTopLevelPipe(RequiredFeatures);
596+
assert(PipeIdx != 0 && PipeIdx != strlen(RequiredFeatures) &&
597+
"Expected feature string of the form 'SVE-EXPR|SME-EXPR'");
598+
StringRef NonStreamingBuiltinGuard = StringRef(RequiredFeatures, PipeIdx);
599+
StringRef StreamingBuiltinGuard = StringRef(RequiredFeatures + PipeIdx + 1);
583600

584-
// We know the builtin requires either some combination of SVE flags, or
585-
// some combination of SME flags, but we need to figure out which part
586-
// of the required features is satisfied by the target features.
587-
//
588-
// For a builtin with target guard 'sve2p1|sme2', if we compile with
589-
// '+sve2p1,+sme', then we know that it satisfies the 'sve2p1' part if we
590-
// evaluate the features for '+sve2p1,+sme,+nosme'.
591-
//
592-
// Similarly, if we compile with '+sve2,+sme2', then we know it satisfies
593-
// the 'sme2' part if we evaluate the features for '+sve2,+sme2,+nosve'.
594-
StringRef BuiltinTargetGuards(
595-
S.Context.BuiltinInfo.getRequiredFeatures(BuiltinID));
596601
bool SatisfiesSVE = Builtin::evaluateRequiredTargetFeatures(
597-
BuiltinTargetGuards, CallerFeatureMapWithoutSME);
602+
NonStreamingBuiltinGuard, CallerFeatures);
598603
bool SatisfiesSME = Builtin::evaluateRequiredTargetFeatures(
599-
BuiltinTargetGuards, CallerFeatureMapWithoutSVE);
604+
StreamingBuiltinGuard, CallerFeatures);
600605

601606
if ((SatisfiesSVE && SatisfiesSME) ||
602607
(SatisfiesSVE && FnType == SemaARM::ArmStreamingCompatible))

clang/utils/TableGen/SveEmitter.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1901,6 +1901,9 @@ void SVEEmitter::createStreamingAttrs(raw_ostream &OS, ACLEKind Kind) {
19011901
if (!Def->isFlagSet(VerifyRuntimeMode) && !Def->getSVEGuard().empty() &&
19021902
!Def->getSMEGuard().empty())
19031903
report_fatal_error("Missing VerifyRuntimeMode flag");
1904+
if (Def->isFlagSet(VerifyRuntimeMode) &&
1905+
(Def->getSVEGuard().empty() || Def->getSMEGuard().empty()))
1906+
report_fatal_error("VerifyRuntimeMode requires SVE and SME guards");
19041907

19051908
if (Def->isFlagSet(IsStreamingFlag))
19061909
StreamingMap["ArmStreaming"].insert(Def->getMangledName());

0 commit comments

Comments
 (0)