llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Alexandros Lamprineas (labrinea) <details> <summary>Changes</summary> The commit https://github.com/llvm/llvm-project/pull/150267 allows the user to override version priority. As a result it is now possible to define an unreachable function version if a higher priority version contains a subset of its FMV features. For example: target_clones("sve;priority=2", "sve2;priority=1") the sve2 version is unreachable, since if you don't have sve we can't have sve2 either. The patch emits a warning about such cases and ignores those versions when generating the resolver. Also removes their definitions. --- Full diff: https://github.com/llvm/llvm-project/pull/171496.diff 4 Files Affected: - (modified) clang/include/clang/Basic/DiagnosticFrontendKinds.td (+4) - (modified) clang/lib/CodeGen/CodeGenFunction.cpp (+4) - (modified) clang/lib/CodeGen/CodeGenModule.cpp (+23) - (added) clang/test/CodeGen/AArch64/fmv-unreachable-version.c (+89) ``````````diff diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td index 9e344160ff934..a2d4564e23285 100644 --- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td @@ -399,6 +399,10 @@ def err_invalid_llvm_ir : Error<"invalid LLVM IR input: %0">; def err_os_unsupport_riscv_fmv : Error< "function multiversioning is currently only supported on Linux">; +def warn_unreachable_version + : Warning<"function version '%0' is unreachable; ignoring version">, + InGroup<FunctionMultiVersioning>; + def warn_hlsl_langstd_minimal : Warning<"support for HLSL language version %0 is incomplete, " "recommend using %1 instead">, diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index ac25bd95f0463..2bf2fd68b860e 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -3143,6 +3143,10 @@ void CodeGenFunction::EmitAArch64MultiVersionResolver( Builder.SetInsertPoint(CurBlock); } + // Skip unreachable versions. + if (RO.Function == nullptr) + continue; + llvm::BasicBlock *RetBlock = createBasicBlock("resolver_return", Resolver); CGBuilderTy RetBuilder(*this, RetBlock); CreateMultiVersionResolverReturn(CGM, Resolver, RetBuilder, RO.Function, diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 1dcf94fc35e07..9864c4cc03274 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -68,6 +68,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Hash.h" #include "llvm/Support/TimeProfiler.h" +#include "llvm/TargetParser/AArch64TargetParser.h" #include "llvm/TargetParser/RISCVISAInfo.h" #include "llvm/TargetParser/Triple.h" #include "llvm/TargetParser/X86TargetParser.h" @@ -4674,6 +4675,7 @@ void CodeGenModule::emitMultiVersionFunctions() { // in this TU. For other architectures it is always emitted. bool ShouldEmitResolver = !getTarget().getTriple().isAArch64(); SmallVector<CodeGenFunction::FMVResolverOption, 10> Options; + llvm::DenseMap<llvm::Function *, const FunctionDecl *> DeclMap; getContext().forEachMultiversionedFunctionVersion( FD, [&](const FunctionDecl *CurFD) { @@ -4684,11 +4686,13 @@ void CodeGenModule::emitMultiVersionFunctions() { assert(getTarget().getTriple().isX86() && "Unsupported target"); TA->getX86AddedFeatures(Feats); llvm::Function *Func = createFunction(CurFD); + DeclMap.insert({Func, CurFD}); Options.emplace_back(Func, Feats, TA->getX86Architecture()); } else if (const auto *TVA = CurFD->getAttr<TargetVersionAttr>()) { if (TVA->isDefaultVersion() && IsDefined) ShouldEmitResolver = true; llvm::Function *Func = createFunction(CurFD); + DeclMap.insert({Func, CurFD}); char Delim = getTarget().getTriple().isAArch64() ? '+' : ','; TVA->getFeatures(Feats, Delim); Options.emplace_back(Func, Feats); @@ -4699,6 +4703,7 @@ void CodeGenModule::emitMultiVersionFunctions() { if (TC->isDefaultVersion(I) && IsDefined) ShouldEmitResolver = true; llvm::Function *Func = createFunction(CurFD, I); + DeclMap.insert({Func, CurFD}); Feats.clear(); if (getTarget().getTriple().isX86()) { TC->getX86Feature(Feats, I); @@ -4744,6 +4749,24 @@ void CodeGenModule::emitMultiVersionFunctions() { const CodeGenFunction::FMVResolverOption &RHS) { return getFMVPriority(TI, LHS).ugt(getFMVPriority(TI, RHS)); }); + + // Diagnose unreachable function versions. + if (getTarget().getTriple().isAArch64()) { + for (auto I = Options.begin() + 1, E = Options.end(); I != E; ++I) { + llvm::APInt RHS = llvm::AArch64::getCpuSupportsMask(I->Features); + if (std::any_of(Options.begin(), I, [RHS](auto RO) { + llvm::APInt LHS = llvm::AArch64::getCpuSupportsMask(RO.Features); + return LHS.isSubsetOf(RHS); + })) { + Diags.Report(DeclMap[I->Function]->getLocation(), + diag::warn_unreachable_version) + << I->Function->getName(); + assert(I->Function->user_empty() && "unexpected users"); + I->Function->eraseFromParent(); + I->Function = nullptr; + } + } + } CodeGenFunction CGF(*this); CGF.EmitMultiVersionResolver(ResolverFunc, Options); diff --git a/clang/test/CodeGen/AArch64/fmv-unreachable-version.c b/clang/test/CodeGen/AArch64/fmv-unreachable-version.c new file mode 100644 index 0000000000000..c9626c5ef34f3 --- /dev/null +++ b/clang/test/CodeGen/AArch64/fmv-unreachable-version.c @@ -0,0 +1,89 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals --include-generated-funcs +// RUN: %clang_cc1 -triple aarch64-linux-gnu -verify -emit-llvm -o - %s | FileCheck %s + +__attribute__((target_version("sve;priority=5"))) int unreachable_versions(void) { return 5; } +// expected-warning@+1 {{function version 'unreachable_versions._MlseMmops' is unreachable; ignoring version}} +__attribute__((target_version("mops+lse;priority=1"))) int unreachable_versions(void) { return 1; } +int foo() { return unreachable_versions(); } +// expected-warning@+1 {{function version 'unreachable_versions._Msve2' is unreachable; ignoring version}} +__attribute__((target_clones("sve2;priority=4", "aes+sve2;priority=3", "lse;priority=2", "default"))) int unreachable_versions(void) { return 0; } +// expected-warning@-1 {{function version 'unreachable_versions._MaesMsve2' is unreachable; ignoring version}} + +//. +// CHECK: @__aarch64_cpu_features = external dso_local global { i64 } +// CHECK: @unreachable_versions = weak_odr ifunc i32 (), ptr @unreachable_versions.resolver +//. +// CHECK: Function Attrs: noinline nounwind optnone vscale_range(1,16) +// CHECK-LABEL: define {{[^@]+}}@unreachable_versions._Msve +// CHECK-SAME: () #[[ATTR0:[0-9]+]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 5 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: define {{[^@]+}}@foo +// CHECK-SAME: () #[[ATTR1:[0-9]+]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[CALL:%.*]] = call i32 @unreachable_versions() +// CHECK-NEXT: ret i32 [[CALL]] +// +// +// CHECK: Function Attrs: noinline nounwind optnone vscale_range(1,16) +// CHECK-LABEL: define {{[^@]+}}@unreachable_versions._Mlse +// CHECK-SAME: () #[[ATTR2:[0-9]+]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 0 +// +// +// CHECK: Function Attrs: noinline nounwind optnone vscale_range(1,16) +// CHECK-LABEL: define {{[^@]+}}@unreachable_versions.default +// CHECK-SAME: () #[[ATTR3:[0-9]+]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 0 +// +// +// CHECK: Function Attrs: disable_sanitizer_instrumentation +// CHECK-LABEL: define {{[^@]+}}@unreachable_versions.resolver +// CHECK-SAME: () #[[ATTR4:[0-9]+]] comdat { +// CHECK-NEXT: resolver_entry: +// CHECK-NEXT: call void @__init_cpu_features_resolver() +// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 1073807616 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 1073807616 +// CHECK-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] +// CHECK-NEXT: br i1 [[TMP3]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] +// CHECK: resolver_return: +// CHECK-NEXT: ret ptr @unreachable_versions._Msve +// CHECK: resolver_else: +// CHECK-NEXT: [[TMP4:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP5:%.*]] = and i64 [[TMP4]], 69793284352 +// CHECK-NEXT: [[TMP6:%.*]] = icmp eq i64 [[TMP5]], 69793284352 +// CHECK-NEXT: [[TMP7:%.*]] = and i1 true, [[TMP6]] +// CHECK-NEXT: [[TMP8:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP9:%.*]] = and i64 [[TMP8]], 69793317632 +// CHECK-NEXT: [[TMP10:%.*]] = icmp eq i64 [[TMP9]], 69793317632 +// CHECK-NEXT: [[TMP11:%.*]] = and i1 true, [[TMP10]] +// CHECK-NEXT: [[TMP12:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP13:%.*]] = and i64 [[TMP12]], 128 +// CHECK-NEXT: [[TMP14:%.*]] = icmp eq i64 [[TMP13]], 128 +// CHECK-NEXT: [[TMP15:%.*]] = and i1 true, [[TMP14]] +// CHECK-NEXT: br i1 [[TMP15]], label [[RESOLVER_RETURN1:%.*]], label [[RESOLVER_ELSE2:%.*]] +// CHECK: resolver_return1: +// CHECK-NEXT: ret ptr @unreachable_versions._Mlse +// CHECK: resolver_else2: +// CHECK-NEXT: [[TMP16:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP17:%.*]] = and i64 [[TMP16]], 576460752303423616 +// CHECK-NEXT: [[TMP18:%.*]] = icmp eq i64 [[TMP17]], 576460752303423616 +// CHECK-NEXT: [[TMP19:%.*]] = and i1 true, [[TMP18]] +// CHECK-NEXT: ret ptr @unreachable_versions.default +// +//. +// CHECK: attributes #[[ATTR0]] = { noinline nounwind optnone vscale_range(1,16) "fmv-features"="P0,P2,sve" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fp-armv8,+fullfp16,+sve" } +// CHECK: attributes #[[ATTR1]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +// CHECK: attributes #[[ATTR2]] = { noinline nounwind optnone vscale_range(1,16) "fmv-features"="P1,lse" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+lse" } +// CHECK: attributes #[[ATTR3]] = { noinline nounwind optnone vscale_range(1,16) "fmv-features" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +// CHECK: attributes #[[ATTR4]] = { disable_sanitizer_instrumentation } +//. +// CHECK: [[META0:![0-9]+]] = !{i32 1, !"wchar_size", i32 4} +// CHECK: [[META1:![0-9]+]] = !{!"{{.*}}clang version {{.*}}"} +//. `````````` </details> https://github.com/llvm/llvm-project/pull/171496 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
