Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions clang/include/clang/Basic/DiagnosticFrontendKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -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">,
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/CodeGen/CodeGenFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
23 changes: 23 additions & 0 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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) {
Expand All @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -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);

Expand Down
89 changes: 89 additions & 0 deletions clang/test/CodeGen/AArch64/fmv-unreachable-version.c
Original file line number Diff line number Diff line change
@@ -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 {{.*}}"}
//.