mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-18 18:56:43 +00:00
[FMV][AArch64] Emit mangled default version if explicitly specified. (#120022)
Currently we need at least one more version other than the default to trigger FMV. However we would like a header file declaration __attribute__((target_version("default"))) void f(void); to guarantee that there will be f.default
This commit is contained in:
parent
eace8269d9
commit
6586c676b4
@ -4283,7 +4283,7 @@ void CodeGenModule::emitMultiVersionFunctions() {
|
||||
getContext().forEachMultiversionedFunctionVersion(
|
||||
FD, [&](const FunctionDecl *CurFD) {
|
||||
llvm::SmallVector<StringRef, 8> Feats;
|
||||
bool IsDefined = CurFD->doesThisDeclarationHaveABody();
|
||||
bool IsDefined = CurFD->getDefinition() != nullptr;
|
||||
|
||||
if (const auto *TA = CurFD->getAttr<TargetAttr>()) {
|
||||
assert(getTarget().getTriple().isX86() && "Unsupported target");
|
||||
|
@ -11073,9 +11073,9 @@ bool Sema::shouldLinkDependentDeclWithPrevious(Decl *D, Decl *PrevDecl) {
|
||||
static bool CheckMultiVersionValue(Sema &S, const FunctionDecl *FD) {
|
||||
const auto *TA = FD->getAttr<TargetAttr>();
|
||||
const auto *TVA = FD->getAttr<TargetVersionAttr>();
|
||||
assert(
|
||||
(TA || TVA) &&
|
||||
"MultiVersion candidate requires a target or target_version attribute");
|
||||
|
||||
assert((TA || TVA) && "Expecting target or target_version attribute");
|
||||
|
||||
const TargetInfo &TargetInfo = S.Context.getTargetInfo();
|
||||
enum ErrType { Feature = 0, Architecture = 1 };
|
||||
|
||||
@ -11372,10 +11372,6 @@ static bool CheckMultiVersionFirstFunction(Sema &S, FunctionDecl *FD) {
|
||||
// otherwise it is treated as a normal function.
|
||||
if (TA && !TA->isDefaultVersion())
|
||||
return false;
|
||||
// The target_version attribute only causes Multiversioning if this
|
||||
// declaration is NOT the default version.
|
||||
if (TVA && TVA->isDefaultVersion())
|
||||
return false;
|
||||
|
||||
if ((TA || TVA) && CheckMultiVersionValue(S, FD)) {
|
||||
FD->setInvalidDecl();
|
||||
@ -11422,26 +11418,24 @@ static bool CheckDeclarationCausesMultiVersioning(Sema &S, FunctionDecl *OldFD,
|
||||
LookupResult &Previous) {
|
||||
assert(!OldFD->isMultiVersion() && "Unexpected MultiVersion");
|
||||
|
||||
const auto *NewTA = NewFD->getAttr<TargetAttr>();
|
||||
const auto *OldTA = OldFD->getAttr<TargetAttr>();
|
||||
const auto *NewTVA = NewFD->getAttr<TargetVersionAttr>();
|
||||
const auto *OldTVA = OldFD->getAttr<TargetVersionAttr>();
|
||||
|
||||
assert((NewTA || NewTVA) && "Excpecting target or target_version attribute");
|
||||
|
||||
// The definitions should be allowed in any order. If we have discovered
|
||||
// a new target version and the preceeding was the default, then add the
|
||||
// corresponding attribute to it.
|
||||
patchDefaultTargetVersion(NewFD, OldFD);
|
||||
|
||||
const auto *NewTA = NewFD->getAttr<TargetAttr>();
|
||||
const auto *NewTVA = NewFD->getAttr<TargetVersionAttr>();
|
||||
const auto *OldTA = OldFD->getAttr<TargetAttr>();
|
||||
|
||||
// If the old decl is NOT MultiVersioned yet, and we don't cause that
|
||||
// to change, this is a simple redeclaration.
|
||||
if (NewTA && !NewTA->isDefaultVersion() &&
|
||||
(!OldTA || OldTA->getFeaturesStr() == NewTA->getFeaturesStr()))
|
||||
return false;
|
||||
|
||||
// The target_version attribute only causes Multiversioning if this
|
||||
// declaration is NOT the default version.
|
||||
if (NewTVA && NewTVA->isDefaultVersion())
|
||||
return false;
|
||||
|
||||
// Otherwise, this decl causes MultiVersioning.
|
||||
if (CheckMultiVersionAdditionalRules(S, OldFD, NewFD, true,
|
||||
NewTVA ? MultiVersionKind::TargetVersion
|
||||
@ -11456,7 +11450,8 @@ static bool CheckDeclarationCausesMultiVersioning(Sema &S, FunctionDecl *OldFD,
|
||||
}
|
||||
|
||||
// If this is 'default', permit the forward declaration.
|
||||
if (NewTA && NewTA->isDefaultVersion() && !OldTA) {
|
||||
if ((NewTA && NewTA->isDefaultVersion() && !OldTA) ||
|
||||
(NewTVA && NewTVA->isDefaultVersion() && !OldTVA)) {
|
||||
Redeclaration = true;
|
||||
OldDecl = OldFD;
|
||||
OldFD->setIsMultiVersion();
|
||||
@ -11464,7 +11459,7 @@ static bool CheckDeclarationCausesMultiVersioning(Sema &S, FunctionDecl *OldFD,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (CheckMultiVersionValue(S, OldFD)) {
|
||||
if ((OldTA || OldTVA) && CheckMultiVersionValue(S, OldFD)) {
|
||||
S.Diag(NewFD->getLocation(), diag::note_multiversioning_caused_here);
|
||||
NewFD->setInvalidDecl();
|
||||
return true;
|
||||
@ -11761,9 +11756,7 @@ static bool CheckMultiVersionAdditionalDecl(
|
||||
// Else, this is simply a non-redecl case. Checking the 'value' is only
|
||||
// necessary in the Target case, since The CPUSpecific/Dispatch cases are
|
||||
// handled in the attribute adding step.
|
||||
if ((NewMVKind == MultiVersionKind::TargetVersion ||
|
||||
NewMVKind == MultiVersionKind::Target) &&
|
||||
CheckMultiVersionValue(S, NewFD)) {
|
||||
if ((NewTA || NewTVA) && CheckMultiVersionValue(S, NewFD)) {
|
||||
NewFD->setInvalidDecl();
|
||||
return true;
|
||||
}
|
||||
@ -11799,6 +11792,12 @@ static bool CheckMultiVersionAdditionalDecl(
|
||||
static bool CheckMultiVersionFunction(Sema &S, FunctionDecl *NewFD,
|
||||
bool &Redeclaration, NamedDecl *&OldDecl,
|
||||
LookupResult &Previous) {
|
||||
const TargetInfo &TI = S.getASTContext().getTargetInfo();
|
||||
|
||||
// Check if FMV is disabled.
|
||||
if (TI.getTriple().isAArch64() && !TI.hasFeature("fmv"))
|
||||
return false;
|
||||
|
||||
const auto *NewTA = NewFD->getAttr<TargetAttr>();
|
||||
const auto *NewTVA = NewFD->getAttr<TargetVersionAttr>();
|
||||
const auto *NewCPUDisp = NewFD->getAttr<CPUDispatchAttr>();
|
||||
@ -11821,14 +11820,12 @@ static bool CheckMultiVersionFunction(Sema &S, FunctionDecl *NewFD,
|
||||
return false;
|
||||
}
|
||||
|
||||
const llvm::Triple &T = S.getASTContext().getTargetInfo().getTriple();
|
||||
|
||||
// Target attribute on AArch64 is not used for multiversioning
|
||||
if (NewTA && T.isAArch64())
|
||||
if (NewTA && TI.getTriple().isAArch64())
|
||||
return false;
|
||||
|
||||
// Target attribute on RISCV is not used for multiversioning
|
||||
if (NewTA && T.isRISCV())
|
||||
if (NewTA && TI.getTriple().isRISCV())
|
||||
return false;
|
||||
|
||||
if (!OldDecl || !OldDecl->getAsFunction() ||
|
||||
|
221
clang/test/CodeGen/AArch64/fmv-mix-explicit-implicit-default.c
Normal file
221
clang/test/CodeGen/AArch64/fmv-mix-explicit-implicit-default.c
Normal file
@ -0,0 +1,221 @@
|
||||
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -emit-llvm -o - %s | FileCheck %s
|
||||
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature -fmv -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK-NOFMV
|
||||
|
||||
int implicit_default_decl_first(void);
|
||||
__attribute__((target_version("default"))) int implicit_default_decl_first(void) { return 1; }
|
||||
int caller1(void) { return implicit_default_decl_first(); }
|
||||
|
||||
__attribute__((target_version("default"))) int explicit_default_def_first(void) { return 2; }
|
||||
int explicit_default_def_first(void);
|
||||
int caller2(void) { return explicit_default_def_first(); }
|
||||
|
||||
int implicit_default_def_first(void) { return 3; }
|
||||
__attribute__((target_version("default"))) int implicit_default_def_first(void);
|
||||
int caller3(void) { return implicit_default_def_first(); }
|
||||
|
||||
__attribute__((target_version("default"))) int explicit_default_decl_first(void);
|
||||
int explicit_default_decl_first(void) { return 4; }
|
||||
int caller4(void) { return explicit_default_decl_first(); }
|
||||
|
||||
int no_def_implicit_default_first(void);
|
||||
__attribute__((target_version("default"))) int no_def_implicit_default_first(void);
|
||||
int caller5(void) { return no_def_implicit_default_first(); }
|
||||
|
||||
__attribute__((target_version("default"))) int no_def_explicit_default_first(void);
|
||||
int no_def_explicit_default_first(void);
|
||||
int caller6(void) { return no_def_explicit_default_first(); }
|
||||
//.
|
||||
// CHECK: @implicit_default_decl_first = weak_odr ifunc i32 (), ptr @implicit_default_decl_first.resolver
|
||||
// CHECK: @explicit_default_def_first = weak_odr ifunc i32 (), ptr @explicit_default_def_first.resolver
|
||||
// CHECK: @implicit_default_def_first = weak_odr ifunc i32 (), ptr @implicit_default_def_first.resolver
|
||||
// CHECK: @explicit_default_decl_first = weak_odr ifunc i32 (), ptr @explicit_default_decl_first.resolver
|
||||
//.
|
||||
// CHECK: Function Attrs: noinline nounwind optnone
|
||||
// CHECK-LABEL: define {{[^@]+}}@implicit_default_decl_first.default
|
||||
// CHECK-SAME: () #[[ATTR0:[0-9]+]] {
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: ret i32 1
|
||||
//
|
||||
//
|
||||
// CHECK: Function Attrs: noinline nounwind optnone
|
||||
// CHECK-LABEL: define {{[^@]+}}@caller1
|
||||
// CHECK-SAME: () #[[ATTR1:[0-9]+]] {
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: [[CALL:%.*]] = call i32 @implicit_default_decl_first()
|
||||
// CHECK-NEXT: ret i32 [[CALL]]
|
||||
//
|
||||
//
|
||||
// CHECK: Function Attrs: noinline nounwind optnone
|
||||
// CHECK-LABEL: define {{[^@]+}}@explicit_default_def_first.default
|
||||
// CHECK-SAME: () #[[ATTR0]] {
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: ret i32 2
|
||||
//
|
||||
//
|
||||
// CHECK: Function Attrs: noinline nounwind optnone
|
||||
// CHECK-LABEL: define {{[^@]+}}@caller2
|
||||
// CHECK-SAME: () #[[ATTR1]] {
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: [[CALL:%.*]] = call i32 @explicit_default_def_first()
|
||||
// CHECK-NEXT: ret i32 [[CALL]]
|
||||
//
|
||||
//
|
||||
// CHECK: Function Attrs: noinline nounwind optnone
|
||||
// CHECK-LABEL: define {{[^@]+}}@implicit_default_def_first.default
|
||||
// CHECK-SAME: () #[[ATTR1]] {
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: ret i32 3
|
||||
//
|
||||
//
|
||||
// CHECK: Function Attrs: noinline nounwind optnone
|
||||
// CHECK-LABEL: define {{[^@]+}}@caller3
|
||||
// CHECK-SAME: () #[[ATTR1]] {
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: [[CALL:%.*]] = call i32 @implicit_default_def_first()
|
||||
// CHECK-NEXT: ret i32 [[CALL]]
|
||||
//
|
||||
//
|
||||
// CHECK: Function Attrs: noinline nounwind optnone
|
||||
// CHECK-LABEL: define {{[^@]+}}@explicit_default_decl_first.default
|
||||
// CHECK-SAME: () #[[ATTR0]] {
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: ret i32 4
|
||||
//
|
||||
//
|
||||
// CHECK: Function Attrs: noinline nounwind optnone
|
||||
// CHECK-LABEL: define {{[^@]+}}@caller4
|
||||
// CHECK-SAME: () #[[ATTR1]] {
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: [[CALL:%.*]] = call i32 @explicit_default_decl_first()
|
||||
// CHECK-NEXT: ret i32 [[CALL]]
|
||||
//
|
||||
//
|
||||
// CHECK: declare i32 @no_def_implicit_default_first() #[[ATTR2:[0-9]+]]
|
||||
//
|
||||
//
|
||||
// CHECK: Function Attrs: noinline nounwind optnone
|
||||
// CHECK-LABEL: define {{[^@]+}}@caller5
|
||||
// CHECK-SAME: () #[[ATTR1]] {
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: [[CALL:%.*]] = call i32 @no_def_implicit_default_first()
|
||||
// CHECK-NEXT: ret i32 [[CALL]]
|
||||
//
|
||||
//
|
||||
// CHECK: declare i32 @no_def_explicit_default_first() #[[ATTR2]]
|
||||
//
|
||||
//
|
||||
// CHECK: Function Attrs: noinline nounwind optnone
|
||||
// CHECK-LABEL: define {{[^@]+}}@caller6
|
||||
// CHECK-SAME: () #[[ATTR1]] {
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: [[CALL:%.*]] = call i32 @no_def_explicit_default_first()
|
||||
// CHECK-NEXT: ret i32 [[CALL]]
|
||||
//
|
||||
//
|
||||
// CHECK-LABEL: define {{[^@]+}}@implicit_default_decl_first.resolver() comdat {
|
||||
// CHECK-NEXT: resolver_entry:
|
||||
// CHECK-NEXT: ret ptr @implicit_default_decl_first.default
|
||||
//
|
||||
//
|
||||
// CHECK-LABEL: define {{[^@]+}}@explicit_default_def_first.resolver() comdat {
|
||||
// CHECK-NEXT: resolver_entry:
|
||||
// CHECK-NEXT: ret ptr @explicit_default_def_first.default
|
||||
//
|
||||
//
|
||||
// CHECK-LABEL: define {{[^@]+}}@implicit_default_def_first.resolver() comdat {
|
||||
// CHECK-NEXT: resolver_entry:
|
||||
// CHECK-NEXT: ret ptr @implicit_default_def_first.default
|
||||
//
|
||||
//
|
||||
// CHECK-LABEL: define {{[^@]+}}@explicit_default_decl_first.resolver() comdat {
|
||||
// CHECK-NEXT: resolver_entry:
|
||||
// CHECK-NEXT: ret ptr @explicit_default_decl_first.default
|
||||
//
|
||||
//
|
||||
// CHECK: declare i32 @no_def_implicit_default_first.default() #[[ATTR2]]
|
||||
//
|
||||
//
|
||||
// CHECK: declare i32 @no_def_explicit_default_first.default() #[[ATTR2]]
|
||||
//
|
||||
//
|
||||
// CHECK-NOFMV: Function Attrs: noinline nounwind optnone
|
||||
// CHECK-NOFMV-LABEL: define {{[^@]+}}@caller1
|
||||
// CHECK-NOFMV-SAME: () #[[ATTR0:[0-9]+]] {
|
||||
// CHECK-NOFMV-NEXT: entry:
|
||||
// CHECK-NOFMV-NEXT: [[CALL:%.*]] = call i32 @implicit_default_decl_first()
|
||||
// CHECK-NOFMV-NEXT: ret i32 [[CALL]]
|
||||
//
|
||||
//
|
||||
// CHECK-NOFMV: Function Attrs: noinline nounwind optnone
|
||||
// CHECK-NOFMV-LABEL: define {{[^@]+}}@implicit_default_decl_first
|
||||
// CHECK-NOFMV-SAME: () #[[ATTR1:[0-9]+]] {
|
||||
// CHECK-NOFMV-NEXT: entry:
|
||||
// CHECK-NOFMV-NEXT: ret i32 1
|
||||
//
|
||||
//
|
||||
// CHECK-NOFMV: Function Attrs: noinline nounwind optnone
|
||||
// CHECK-NOFMV-LABEL: define {{[^@]+}}@caller2
|
||||
// CHECK-NOFMV-SAME: () #[[ATTR0]] {
|
||||
// CHECK-NOFMV-NEXT: entry:
|
||||
// CHECK-NOFMV-NEXT: [[CALL:%.*]] = call i32 @explicit_default_def_first()
|
||||
// CHECK-NOFMV-NEXT: ret i32 [[CALL]]
|
||||
//
|
||||
//
|
||||
// CHECK-NOFMV: Function Attrs: noinline nounwind optnone
|
||||
// CHECK-NOFMV-LABEL: define {{[^@]+}}@explicit_default_def_first
|
||||
// CHECK-NOFMV-SAME: () #[[ATTR1]] {
|
||||
// CHECK-NOFMV-NEXT: entry:
|
||||
// CHECK-NOFMV-NEXT: ret i32 2
|
||||
//
|
||||
//
|
||||
// CHECK-NOFMV: Function Attrs: noinline nounwind optnone
|
||||
// CHECK-NOFMV-LABEL: define {{[^@]+}}@implicit_default_def_first
|
||||
// CHECK-NOFMV-SAME: () #[[ATTR0]] {
|
||||
// CHECK-NOFMV-NEXT: entry:
|
||||
// CHECK-NOFMV-NEXT: ret i32 3
|
||||
//
|
||||
//
|
||||
// CHECK-NOFMV: Function Attrs: noinline nounwind optnone
|
||||
// CHECK-NOFMV-LABEL: define {{[^@]+}}@caller3
|
||||
// CHECK-NOFMV-SAME: () #[[ATTR0]] {
|
||||
// CHECK-NOFMV-NEXT: entry:
|
||||
// CHECK-NOFMV-NEXT: [[CALL:%.*]] = call i32 @implicit_default_def_first()
|
||||
// CHECK-NOFMV-NEXT: ret i32 [[CALL]]
|
||||
//
|
||||
//
|
||||
// CHECK-NOFMV: Function Attrs: noinline nounwind optnone
|
||||
// CHECK-NOFMV-LABEL: define {{[^@]+}}@caller4
|
||||
// CHECK-NOFMV-SAME: () #[[ATTR0]] {
|
||||
// CHECK-NOFMV-NEXT: entry:
|
||||
// CHECK-NOFMV-NEXT: [[CALL:%.*]] = call i32 @explicit_default_decl_first()
|
||||
// CHECK-NOFMV-NEXT: ret i32 [[CALL]]
|
||||
//
|
||||
//
|
||||
// CHECK-NOFMV: Function Attrs: noinline nounwind optnone
|
||||
// CHECK-NOFMV-LABEL: define {{[^@]+}}@explicit_default_decl_first
|
||||
// CHECK-NOFMV-SAME: () #[[ATTR1]] {
|
||||
// CHECK-NOFMV-NEXT: entry:
|
||||
// CHECK-NOFMV-NEXT: ret i32 4
|
||||
//
|
||||
//
|
||||
// CHECK-NOFMV: Function Attrs: noinline nounwind optnone
|
||||
// CHECK-NOFMV-LABEL: define {{[^@]+}}@caller5
|
||||
// CHECK-NOFMV-SAME: () #[[ATTR0]] {
|
||||
// CHECK-NOFMV-NEXT: entry:
|
||||
// CHECK-NOFMV-NEXT: [[CALL:%.*]] = call i32 @no_def_implicit_default_first()
|
||||
// CHECK-NOFMV-NEXT: ret i32 [[CALL]]
|
||||
//
|
||||
//
|
||||
// CHECK-NOFMV: declare i32 @no_def_implicit_default_first() #[[ATTR2:[0-9]+]]
|
||||
//
|
||||
//
|
||||
// CHECK-NOFMV: Function Attrs: noinline nounwind optnone
|
||||
// CHECK-NOFMV-LABEL: define {{[^@]+}}@caller6
|
||||
// CHECK-NOFMV-SAME: () #[[ATTR0]] {
|
||||
// CHECK-NOFMV-NEXT: entry:
|
||||
// CHECK-NOFMV-NEXT: [[CALL:%.*]] = call i32 @no_def_explicit_default_first()
|
||||
// CHECK-NOFMV-NEXT: ret i32 [[CALL]]
|
||||
//
|
||||
//
|
||||
// CHECK-NOFMV: declare i32 @no_def_explicit_default_first() #[[ATTR2]]
|
||||
//.
|
@ -143,10 +143,12 @@ int caller(void) { return used_def_without_default_decl() + used_decl_without_de
|
||||
// CHECK: @fmv_d = internal ifunc i32 (), ptr @fmv_d.resolver
|
||||
// CHECK: @fmv_c = weak_odr ifunc void (), ptr @fmv_c.resolver
|
||||
// CHECK: @fmv_inline = weak_odr ifunc i32 (), ptr @fmv_inline.resolver
|
||||
// CHECK: @reca = weak_odr ifunc void (), ptr @reca.resolver
|
||||
// CHECK: @unused_with_default_def = weak_odr ifunc i32 (), ptr @unused_with_default_def.resolver
|
||||
// CHECK: @unused_with_implicit_default_def = weak_odr ifunc i32 (), ptr @unused_with_implicit_default_def.resolver
|
||||
// CHECK: @unused_with_implicit_forward_default_def = weak_odr ifunc i32 (), ptr @unused_with_implicit_forward_default_def.resolver
|
||||
// CHECK: @default_def_with_version_decls = weak_odr ifunc i32 (), ptr @default_def_with_version_decls.resolver
|
||||
// CHECK: @recb = weak_odr ifunc void (), ptr @recb.resolver
|
||||
//.
|
||||
// CHECK: Function Attrs: noinline nounwind optnone
|
||||
// CHECK-LABEL: define {{[^@]+}}@fmv._MflagmMfp16fmlMrng
|
||||
@ -287,8 +289,15 @@ int caller(void) { return used_def_without_default_decl() + used_decl_without_de
|
||||
//
|
||||
//
|
||||
// CHECK: Function Attrs: noinline nounwind optnone
|
||||
// CHECK-LABEL: define {{[^@]+}}@fmv_default.default
|
||||
// CHECK-SAME: () #[[ATTR9]] {
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: ret i32 111
|
||||
//
|
||||
//
|
||||
// CHECK: Function Attrs: noinline nounwind optnone
|
||||
// CHECK-LABEL: define {{[^@]+}}@fmv_c._Mssbs
|
||||
// CHECK-SAME: () #[[ATTR16:[0-9]+]] {
|
||||
// CHECK-SAME: () #[[ATTR17:[0-9]+]] {
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: ret void
|
||||
//
|
||||
@ -313,13 +322,6 @@ int caller(void) { return used_def_without_default_decl() + used_decl_without_de
|
||||
//
|
||||
//
|
||||
// CHECK: Function Attrs: noinline nounwind optnone
|
||||
// CHECK-LABEL: define {{[^@]+}}@fmv_default
|
||||
// CHECK-SAME: () #[[ATTR9]] {
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: ret i32 111
|
||||
//
|
||||
//
|
||||
// CHECK: Function Attrs: noinline nounwind optnone
|
||||
// CHECK-LABEL: define {{[^@]+}}@recur
|
||||
// CHECK-SAME: () #[[ATTR15]] {
|
||||
// CHECK-NEXT: entry:
|
||||
@ -895,6 +897,19 @@ int caller(void) { return used_def_without_default_decl() + used_decl_without_de
|
||||
// CHECK-NEXT: ret ptr @fmv_inline.default
|
||||
//
|
||||
//
|
||||
// CHECK: Function Attrs: noinline nounwind optnone
|
||||
// CHECK-LABEL: define {{[^@]+}}@reca.default
|
||||
// CHECK-SAME: () #[[ATTR9]] {
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: call void @recb()
|
||||
// CHECK-NEXT: ret void
|
||||
//
|
||||
//
|
||||
// CHECK-LABEL: define {{[^@]+}}@reca.resolver() comdat {
|
||||
// CHECK-NEXT: resolver_entry:
|
||||
// CHECK-NEXT: ret ptr @reca.default
|
||||
//
|
||||
//
|
||||
// CHECK-LABEL: define {{[^@]+}}@unused_with_default_def.resolver() comdat {
|
||||
// CHECK-NEXT: resolver_entry:
|
||||
// CHECK-NEXT: call void @__init_cpu_features_resolver()
|
||||
@ -959,6 +974,26 @@ int caller(void) { return used_def_without_default_decl() + used_decl_without_de
|
||||
// CHECK-NEXT: ret ptr @default_def_with_version_decls.default
|
||||
//
|
||||
//
|
||||
// CHECK: Function Attrs: noinline nounwind optnone
|
||||
// CHECK-LABEL: define {{[^@]+}}@recb.default
|
||||
// CHECK-SAME: () #[[ATTR9]] {
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: call void @func()
|
||||
// CHECK-NEXT: ret void
|
||||
//
|
||||
//
|
||||
// CHECK: Function Attrs: noinline nounwind optnone
|
||||
// CHECK-LABEL: define {{[^@]+}}@func
|
||||
// CHECK-SAME: () #[[ATTR15]] {
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: ret void
|
||||
//
|
||||
//
|
||||
// CHECK-LABEL: define {{[^@]+}}@recb.resolver() comdat {
|
||||
// CHECK-NEXT: resolver_entry:
|
||||
// CHECK-NEXT: ret ptr @recb.default
|
||||
//
|
||||
//
|
||||
// CHECK-NOFMV: Function Attrs: noinline nounwind optnone
|
||||
// CHECK-NOFMV-LABEL: define {{[^@]+}}@foo
|
||||
// CHECK-NOFMV-SAME: () #[[ATTR0:[0-9]+]] {
|
||||
|
@ -28,34 +28,40 @@ __attribute((target_version("mops"))) int bar() { return 1; }
|
||||
// CHECK: @_ZN4Name3fooEv = weak_odr ifunc i32 (), ptr @_ZN4Name3fooEv.resolver
|
||||
// CHECK: @_ZN3Foo3barEv = weak_odr ifunc i32 (), ptr @_ZN3Foo3barEv.resolver
|
||||
//.
|
||||
// CHECK-LABEL: define dso_local noundef i32 @_ZN4Name3fooEv._Msve(
|
||||
// CHECK-LABEL: define dso_local noundef i32 @_ZN4Name3fooEv.default(
|
||||
// CHECK-SAME: ) #[[ATTR0:[0-9]+]] {
|
||||
// CHECK-NEXT: [[ENTRY:.*:]]
|
||||
// CHECK-NEXT: ret i32 0
|
||||
//
|
||||
//
|
||||
// CHECK-LABEL: define dso_local noundef i32 @_ZN4Name3fooEv._Msve(
|
||||
// CHECK-SAME: ) #[[ATTR1:[0-9]+]] {
|
||||
// CHECK-NEXT: [[ENTRY:.*:]]
|
||||
// CHECK-NEXT: ret i32 1
|
||||
//
|
||||
//
|
||||
// CHECK-LABEL: define dso_local noundef i32 @_Z3barv(
|
||||
// CHECK-SAME: ) #[[ATTR1:[0-9]+]] {
|
||||
// CHECK-SAME: ) #[[ATTR2:[0-9]+]] {
|
||||
// CHECK-NEXT: [[ENTRY:.*:]]
|
||||
// CHECK-NEXT: [[CALL:%.*]] = call noundef i32 @_ZN4Name3fooEv()
|
||||
// CHECK-NEXT: ret i32 [[CALL]]
|
||||
//
|
||||
//
|
||||
// CHECK-LABEL: define dso_local noundef i32 @_ZN9OtherName3fooEv._Msve(
|
||||
// CHECK-SAME: ) #[[ATTR0]] {
|
||||
// CHECK-SAME: ) #[[ATTR1]] {
|
||||
// CHECK-NEXT: [[ENTRY:.*:]]
|
||||
// CHECK-NEXT: ret i32 2
|
||||
//
|
||||
//
|
||||
// CHECK-LABEL: define dso_local noundef i32 @_Z3bazv(
|
||||
// CHECK-SAME: ) #[[ATTR1]] {
|
||||
// CHECK-SAME: ) #[[ATTR2]] {
|
||||
// CHECK-NEXT: [[ENTRY:.*:]]
|
||||
// CHECK-NEXT: [[CALL:%.*]] = call noundef i32 @_ZN9OtherName3fooEv()
|
||||
// CHECK-NEXT: ret i32 [[CALL]]
|
||||
//
|
||||
//
|
||||
// CHECK-LABEL: define dso_local noundef i32 @_ZN3Foo3barEv.default(
|
||||
// CHECK-SAME: ) #[[ATTR3:[0-9]+]] {
|
||||
// CHECK-SAME: ) #[[ATTR0]] {
|
||||
// CHECK-NEXT: [[ENTRY:.*:]]
|
||||
// CHECK-NEXT: ret i32 0
|
||||
//
|
||||
@ -66,12 +72,6 @@ __attribute((target_version("mops"))) int bar() { return 1; }
|
||||
// CHECK-NEXT: ret i32 1
|
||||
//
|
||||
//
|
||||
// CHECK-LABEL: define dso_local noundef i32 @_ZN4Name3fooEv.default(
|
||||
// CHECK-SAME: ) #[[ATTR3]] {
|
||||
// CHECK-NEXT: [[ENTRY:.*:]]
|
||||
// CHECK-NEXT: ret i32 0
|
||||
//
|
||||
//
|
||||
// CHECK-LABEL: define weak_odr ptr @_ZN4Name3fooEv.resolver() comdat {
|
||||
// CHECK-NEXT: [[RESOLVER_ENTRY:.*:]]
|
||||
// CHECK-NEXT: call void @__init_cpu_features_resolver()
|
||||
|
@ -102,13 +102,17 @@ int __attribute__((target_version("sha2"))) combine(void) { return 1; }
|
||||
// expected-error@+1 {{multiversioned function declaration has a different calling convention}}
|
||||
int __attribute__((aarch64_vector_pcs, target_version("sha3"))) combine(void) { return 2; }
|
||||
|
||||
// expected-error@+1 {{multiversioned function must have a prototype}}
|
||||
int __attribute__((target_version("fp+aes+rcpc"))) unspec_args() { return -1; }
|
||||
// expected-error@-1 {{multiversioned function must have a prototype}}
|
||||
// expected-note@+1 {{function multiversioning caused by this declaration}}
|
||||
int __attribute__((target_version("default"))) unspec_args() { return 0; }
|
||||
int cargs() { return unspec_args(); }
|
||||
|
||||
// expected-error@+1 {{multiversioned function must have a prototype}}
|
||||
int unspec_args_implicit_default_first();
|
||||
// expected-error@-1 {{multiversioned function must have a prototype}}
|
||||
// expected-note@+1 {{function multiversioning caused by this declaration}}
|
||||
int __attribute__((target_version("aes"))) unspec_args_implicit_default_first() { return -1; }
|
||||
// expected-note@+1 {{function multiversioning caused by this declaration}}
|
||||
int __attribute__((target_version("default"))) unspec_args_implicit_default_first() { return 0; }
|
||||
|
@ -57,7 +57,7 @@ int __attribute__((target_version("fp16fml"))) diff_type3(void) noexcept(false)
|
||||
int __attribute__((target_version("sve2-sha3"))) diff_type3(void) noexcept(true) { return 2; }
|
||||
|
||||
template <typename T> int __attribute__((target_version("default"))) temp(T) { return 1; }
|
||||
|
||||
// expected-error@-1 {{attribute 'target_version' multiversioned functions do not yet support function templates}}
|
||||
template <typename T> int __attribute__((target_version("simd"))) temp1(T) { return 1; }
|
||||
// expected-error@-1 {{attribute 'target_version' multiversioned functions do not yet support function templates}}
|
||||
|
||||
@ -68,6 +68,7 @@ int __attribute__((target_version("aes"))) extc(void) { return 1; }
|
||||
int __attribute__((target_version("lse"))) extc(void) { return 1; }
|
||||
|
||||
auto __attribute__((target_version("default"))) ret1(void) { return 1; }
|
||||
// expected-error@-1 {{attribute 'target_version' multiversioned functions do not yet support deduced return types}}
|
||||
auto __attribute__((target_version("dpb"))) ret2(void) { return 1; }
|
||||
// expected-error@-1 {{attribute 'target_version' multiversioned functions do not yet support deduced return types}}
|
||||
auto __attribute__((target_version("dpb2"))) ret3(void) -> int { return 1; }
|
||||
@ -84,6 +85,7 @@ class Cls {
|
||||
// expected-error@-1 {{attribute 'target_version' multiversioned functions do not yet support deleted functions}}
|
||||
|
||||
virtual void __attribute__((target_version("default"))) vfunc();
|
||||
// expected-error@-1 {{attribute 'target_version' multiversioned functions do not yet support virtual functions}}
|
||||
virtual void __attribute__((target_version("sm4"))) vfunc1();
|
||||
// expected-error@-1 {{attribute 'target_version' multiversioned functions do not yet support virtual functions}}
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user