From 802e1c6b0b6e343d97a2549d05e0cb33dec09363 Mon Sep 17 00:00:00 2001 From: Jon Roelofs Date: Tue, 28 Nov 2023 10:38:32 -0800 Subject: [PATCH 01/13] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20?= =?UTF-8?q?changes=20to=20main=20this=20commit=20is=20based=20on?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Created using spr 1.3.4 [skip ci] --- clang/include/clang/Basic/Attr.td | 5 +- clang/include/clang/Basic/AttrDocs.td | 4 +- clang/include/clang/Basic/TargetInfo.h | 2 + clang/test/CodeGen/attr-target-mv-va-args.c | 19 ++ clang/test/CodeGen/ifunc.c | 8 + llvm/docs/LangRef.rst | 7 +- llvm/include/llvm/CodeGen/AsmPrinter.h | 6 +- llvm/lib/CodeGen/GlobalISel/CallLowering.cpp | 7 +- llvm/lib/IR/Verifier.cpp | 12 +- llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp | 308 ++++++++++++++++++ llvm/lib/Target/X86/X86AsmPrinter.cpp | 28 ++ llvm/lib/Target/X86/X86AsmPrinter.h | 1 + .../AArch64/GlobalISel/call-lowering-ifunc.ll | 37 +++ llvm/test/CodeGen/AArch64/addrsig-macho.ll | 4 +- llvm/test/CodeGen/AArch64/ifunc-asm.ll | 82 +++++ llvm/test/CodeGen/X86/ifunc-asm.ll | 28 +- llvm/test/Verifier/ifunc-macho.ll | 42 +++ 17 files changed, 575 insertions(+), 25 deletions(-) create mode 100644 llvm/test/CodeGen/AArch64/GlobalISel/call-lowering-ifunc.ll create mode 100644 llvm/test/CodeGen/AArch64/ifunc-asm.ll create mode 100644 llvm/test/Verifier/ifunc-macho.ll diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 03ed6accf700c..cef9f5578fa2b 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -455,6 +455,9 @@ def TargetMicrosoftCXXABI : TargetArch<["x86", "x86_64", "arm", "thumb", "aarch6 def TargetELF : TargetSpec { let ObjectFormats = ["ELF"]; } +def TargetELFOrMachO : TargetSpec { + let ObjectFormats = ["ELF", "MachO"]; +} def TargetSupportsInitPriority : TargetSpec { let CustomCode = [{ !Target.getTriple().isOSzOS() }]; @@ -1665,7 +1668,7 @@ def IBOutletCollection : InheritableAttr { let Documentation = [Undocumented]; } -def IFunc : Attr, TargetSpecificAttr { +def IFunc : Attr, TargetSpecificAttr { let Spellings = [GCC<"ifunc">]; let Args = [StringArgument<"Resolver">]; let Subjects = SubjectList<[Function]>; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index be74535e28d8a..4c4c4eb606fb0 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -5408,7 +5408,9 @@ considered inline. Not all targets support this attribute. ELF target support depends on both the linker and runtime linker, and is available in at least lld 4.0 and later, binutils 2.20.1 and later, glibc v2.11.1 and later, and FreeBSD 9.1 and later. -Non-ELF targets currently do not support this attribute. +MachO targets support it, but with slightly different semantics: the resolver is +run at first call, instead of at load time by the runtime linker. Targets other +than ELF and MachO currently do not support this attribute. }]; } diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h index 41f3c2e403cbe..1fe2a18cd5dc9 100644 --- a/clang/include/clang/Basic/TargetInfo.h +++ b/clang/include/clang/Basic/TargetInfo.h @@ -1424,6 +1424,8 @@ class TargetInfo : public TransferrableTargetInfo, /// Identify whether this target supports IFuncs. bool supportsIFunc() const { + if (getTriple().isOSBinFormatMachO()) + return true; return getTriple().isOSBinFormatELF() && ((getTriple().isOSLinux() && !getTriple().isMusl()) || getTriple().isOSFreeBSD()); diff --git a/clang/test/CodeGen/attr-target-mv-va-args.c b/clang/test/CodeGen/attr-target-mv-va-args.c index 96821c610235b..dbf5a74205c4c 100644 --- a/clang/test/CodeGen/attr-target-mv-va-args.c +++ b/clang/test/CodeGen/attr-target-mv-va-args.c @@ -3,6 +3,7 @@ // RUN: %clang_cc1 -triple x86_64-windows-pc -emit-llvm %s -o - | FileCheck %s --check-prefixes=NO-IFUNC,WINDOWS // RUN: %clang_cc1 -triple x86_64-linux-musl -emit-llvm %s -o - | FileCheck %s --check-prefixes=NO-IFUNC,NO-IFUNC-ELF // RUN: %clang_cc1 -triple x86_64-fuchsia -emit-llvm %s -o - | FileCheck %s --check-prefixes=NO-IFUNC,NO-IFUNC-ELF +// RUN: %clang_cc1 -triple x86_64-apple-macho -emit-llvm %s -o - | FileCheck %s --check-prefix=IFUNC-MACHO int __attribute__((target("sse4.2"))) foo(int i, ...) { return 0; } int __attribute__((target("arch=sandybridge"))) foo(int i, ...); int __attribute__((target("arch=ivybridge"))) foo(int i, ...) {return 1;} @@ -30,6 +31,24 @@ int bar(void) { // IFUNC-ELF: ret ptr @foo // IFUNC-ELF: declare i32 @foo.arch_sandybridge(i32 noundef, ...) +// IFUNC-MACHO: @foo.ifunc = weak_odr ifunc i32 (i32, ...), ptr @foo.resolver +// IFUNC-MACHO: define{{.*}} i32 @foo.sse4.2(i32 noundef %i, ...) +// IFUNC-MACHO: ret i32 0 +// IFUNC-MACHO: define{{.*}} i32 @foo.arch_ivybridge(i32 noundef %i, ...) +// IFUNC-MACHO: ret i32 1 +// IFUNC-MACHO: define{{.*}} i32 @foo(i32 noundef %i, ...) +// IFUNC-MACHO: ret i32 2 +// IFUNC-MACHO: define{{.*}} i32 @bar() +// IFUNC-MACHO: call i32 (i32, ...) @foo.ifunc(i32 noundef 1, i32 noundef 97, double +// IFUNC-MACHO: call i32 (i32, ...) @foo.ifunc(i32 noundef 2, double noundef 2.2{{[0-9Ee+]+}}, ptr noundef + +// IFUNC-MACHO: define weak_odr ptr @foo.resolver() +// IFUNC-MACHO: ret ptr @foo.arch_sandybridge +// IFUNC-MACHO: ret ptr @foo.arch_ivybridge +// IFUNC-MACHO: ret ptr @foo.sse4.2 +// IFUNC-MACHO: ret ptr @foo +// IFUNC-MACHO: declare i32 @foo.arch_sandybridge(i32 noundef, ...) + // NO-IFUNC: define dso_local i32 @foo.sse4.2(i32 noundef %i, ...) // NO-IFUNC: ret i32 0 // NO-IFUNC: define dso_local i32 @foo.arch_ivybridge(i32 noundef %i, ...) diff --git a/clang/test/CodeGen/ifunc.c b/clang/test/CodeGen/ifunc.c index 0b0a0549620f8..99d60dc0ea85d 100644 --- a/clang/test/CodeGen/ifunc.c +++ b/clang/test/CodeGen/ifunc.c @@ -3,6 +3,10 @@ // RUN: %clang_cc1 -triple i386-unknown-linux-gnu -fsanitize=thread -O2 -emit-llvm -o - %s | FileCheck %s --check-prefix=SAN // RUN: %clang_cc1 -triple i386-unknown-linux-gnu -fsanitize=address -O2 -emit-llvm -o - %s | FileCheck %s --check-prefix=SAN // RUN: %clang_cc1 -triple i386-unknown-linux-gnu -fsanitize=memory -O2 -emit-llvm -o - %s | FileCheck %s --check-prefix=SAN +// RUN: %clang_cc1 -triple x86_64-apple-macosx -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-apple-macosx -O2 -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-apple-macosx -fsanitize=thread -O2 -emit-llvm -o - %s | FileCheck %s --check-prefix=MACSAN +// RUN: %clang_cc1 -triple x86_64-apple-macosx -fsanitize=address -O2 -emit-llvm -o - %s | FileCheck %s --check-prefix=MACSAN int foo(int) __attribute__ ((ifunc("foo_ifunc"))); @@ -44,9 +48,13 @@ void* goo_ifunc(void) { // CHECK: call void @goo() // SAN: define internal nonnull ptr @foo_ifunc() #[[#FOO_IFUNC:]] { +// MACSAN: define internal nonnull ptr @foo_ifunc() #[[#FOO_IFUNC:]] { // SAN: define dso_local noalias ptr @goo_ifunc() #[[#GOO_IFUNC:]] { +// MACSAN: define noalias ptr @goo_ifunc() #[[#GOO_IFUNC:]] { // SAN-DAG: attributes #[[#FOO_IFUNC]] = {{{.*}} disable_sanitizer_instrumentation {{.*}} +// MACSAN-DAG: attributes #[[#FOO_IFUNC]] = {{{.*}} disable_sanitizer_instrumentation {{.*}} // SAN-DAG: attributes #[[#GOO_IFUNC]] = {{{.*}} disable_sanitizer_instrumentation {{.*}} +// MACSAN-DAG: attributes #[[#GOO_IFUNC]] = {{{.*}} disable_sanitizer_instrumentation {{.*}} diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst index e448c5ed5c5d9..cb222e979db29 100644 --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -934,10 +934,11 @@ IFuncs ------- IFuncs, like as aliases, don't create any new data or func. They are just a new -symbol that dynamic linker resolves at runtime by calling a resolver function. +symbol that is resolved at runtime by calling a resolver function. -IFuncs have a name and a resolver that is a function called by dynamic linker -that returns address of another function associated with the name. +On ELF platforms, IFuncs are resolved by the dynamic linker at load time. On +MachO platforms, they are lowered in terms of ``.symbol_resolver``s, which +lazily resolve the callee the first time they are called. IFunc may have an optional :ref:`linkage type ` and an optional :ref:`visibility style `. diff --git a/llvm/include/llvm/CodeGen/AsmPrinter.h b/llvm/include/llvm/CodeGen/AsmPrinter.h index 2731ef452c79c..48fa6c478464c 100644 --- a/llvm/include/llvm/CodeGen/AsmPrinter.h +++ b/llvm/include/llvm/CodeGen/AsmPrinter.h @@ -882,7 +882,11 @@ class AsmPrinter : public MachineFunctionPass { GCMetadataPrinter *getOrCreateGCPrinter(GCStrategy &S); void emitGlobalAlias(Module &M, const GlobalAlias &GA); - void emitGlobalIFunc(Module &M, const GlobalIFunc &GI); + +protected: + virtual void emitGlobalIFunc(Module &M, const GlobalIFunc &GI); + +private: /// This method decides whether the specified basic block requires a label. bool shouldEmitLabelForBasicBlock(const MachineBasicBlock &MBB) const; diff --git a/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp b/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp index 2527b14312896..e0080b145d4f9 100644 --- a/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp +++ b/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp @@ -144,7 +144,12 @@ bool CallLowering::lowerCall(MachineIRBuilder &MIRBuilder, const CallBase &CB, // Try looking through a bitcast from one function type to another. // Commonly happens with calls to objc_msgSend(). const Value *CalleeV = CB.getCalledOperand()->stripPointerCasts(); - if (const Function *F = dyn_cast(CalleeV)) + if (const GlobalIFunc *IF = dyn_cast(CalleeV); + IF && MF.getTarget().getTargetTriple().isOSBinFormatMachO()) { + // ld64 requires that .symbol_resolvers to be called via a stub, so these + // must always be a diret call. + Info.Callee = MachineOperand::CreateGA(IF, 0); + } else if (const Function *F = dyn_cast(CalleeV)) Info.Callee = MachineOperand::CreateGA(F, 0); else Info.Callee = MachineOperand::CreateReg(GetCalleeReg(), false); diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index 5560c037aa3ee..94e76a43bf38d 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -959,6 +959,7 @@ void Verifier::visitGlobalIFunc(const GlobalIFunc &GI) { GlobalIFunc::getResolverFunctionType(GI.getValueType()); Check(ResolverTy == ResolverFuncTy->getPointerTo(GI.getAddressSpace()), "IFunc resolver has incorrect type", &GI); + } void Verifier::visitNamedMDNode(const NamedMDNode &NMD) { @@ -2239,13 +2240,10 @@ void Verifier::verifyFunctionAttrs(FunctionType *FT, AttributeList Attrs, } // Check EVEX512 feature. - if (MaxParameterWidth >= 512 && Attrs.hasFnAttr("target-features")) { - Triple T(M.getTargetTriple()); - if (T.isX86()) { - StringRef TF = Attrs.getFnAttr("target-features").getValueAsString(); - Check(!TF.contains("+avx512f") || !TF.contains("-evex512"), - "512-bit vector arguments require 'evex512' for AVX512", V); - } + if (MaxParameterWidth >= 512 && Attrs.hasFnAttr("target-features") && TT.isX86()) { + StringRef TF = Attrs.getFnAttr("target-features").getValueAsString(); + Check(!TF.contains("+avx512f") || !TF.contains("-evex512"), + "512-bit vector arguments require 'evex512' for AVX512", V); } checkUnsignedBaseTenFuncAttr(Attrs, "patchable-function-prefix", V); diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp index f4d3a85f34c88..2dab8e126c9ab 100644 --- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp +++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp @@ -30,6 +30,7 @@ #include "llvm/ADT/Twine.h" #include "llvm/BinaryFormat/COFF.h" #include "llvm/BinaryFormat/ELF.h" +#include "llvm/BinaryFormat/MachO.h" #include "llvm/CodeGen/AsmPrinter.h" #include "llvm/CodeGen/FaultMaps.h" #include "llvm/CodeGen/MachineBasicBlock.h" @@ -47,10 +48,12 @@ #include "llvm/MC/MCInst.h" #include "llvm/MC/MCInstBuilder.h" #include "llvm/MC/MCSectionELF.h" +#include "llvm/MC/MCSectionMachO.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/TargetRegistry.h" #include "llvm/Support/Casting.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetMachine.h" @@ -68,6 +71,22 @@ using namespace llvm; namespace { +enum class IFuncLowering { SymbolResolverIfSupported, SymbolResolverAlways, SymbolResolverNever }; + +static cl::opt PreferredIFuncLowering( + "arm64-darwin-ifunc-symbol_resolver", cl::init(IFuncLowering::SymbolResolverNever), + cl::desc("Pick the lowering for ifuncs on darwin platforms"), cl::Hidden, + cl::values( + clEnumValN( + IFuncLowering::SymbolResolverIfSupported, "if_supported", + "Use .symbol_resolver's when known to be supported by the linker."), + clEnumValN(IFuncLowering::SymbolResolverAlways, "always", + "Always use .symbol_resolvers. NOTE: this might not be " + "supported by the linker in all cases."), + clEnumValN(IFuncLowering::SymbolResolverNever, "never", + "Use a manual lowering, doing what the linker would have " + "done, but in the compiler."))); + class AArch64AsmPrinter : public AsmPrinter { AArch64MCInstLower MCInstLowering; FaultMaps FM; @@ -198,6 +217,11 @@ class AArch64AsmPrinter : public AsmPrinter { bool shouldEmitWeakSwiftAsyncExtendedFramePointerFlags() const override { return ShouldEmitWeakSwiftAsyncExtendedFramePointerFlags; } + + void emitGlobalIFunc(Module &M, const GlobalIFunc &GI) override; + + void emitLinkerSymbolResolver(Module &M, const GlobalIFunc &GI); + void emitManualSymbolResolver(Module &M, const GlobalIFunc &GI); }; } // end anonymous namespace @@ -1809,6 +1833,290 @@ void AArch64AsmPrinter::emitInstruction(const MachineInstr *MI) { EmitToStreamer(*OutStreamer, TmpInst); } +void AArch64AsmPrinter::emitLinkerSymbolResolver(Module &M, + const GlobalIFunc &GI) { + OutStreamer->switchSection(OutContext.getObjectFileInfo()->getTextSection()); + + MCSymbol *Name = getSymbol(&GI); + + // NOTE: non-global .symbol_resolvers are not yet supported by Darwin linkers + + if (GI.hasExternalLinkage() || !MAI->getWeakRefDirective()) + OutStreamer->emitSymbolAttribute(Name, MCSA_Global); + else if (GI.hasWeakLinkage() || GI.hasLinkOnceLinkage()) + OutStreamer->emitSymbolAttribute(Name, MCSA_WeakReference); + else + assert(GI.hasLocalLinkage() && "Invalid ifunc linkage"); + + OutStreamer->emitCodeAlignment(Align(4), STI); + OutStreamer->emitLabel(Name); + OutStreamer->emitSymbolAttribute(Name, MCSA_SymbolResolver); + emitVisibility(Name, GI.getVisibility()); + + // ld-prime does not seem to support aliases of symbol resolvers, so we have to + // tail call the resolver manually. + OutStreamer->emitInstruction( + MCInstBuilder(AArch64::B) + .addOperand(MCOperand::createExpr(lowerConstant(GI.getResolver()))), + *STI); +} + +/// \brief Emit a manually-constructed .symbol_resolver that implements the +/// symbol resolution duties of the IFunc. +/// +/// Normally, this would be handled by linker magic, but unfortunately there are +/// a few limitations in ld64 and ld-prime's implementation of .symbol_resolver +/// that mean we can't always use them: +/// +/// * resolvers cannot be the target of an alias +/// * resolvers cannot have private linkage +/// * resolvers cannot have linkonce linkage +/// * resolvers cannot appear in executables +/// * resolvers cannot appear in bundles +/// +/// This works around that by emitting a close approximation of what the linker +/// would have done. +void AArch64AsmPrinter::emitManualSymbolResolver(Module &M, + const GlobalIFunc &GI) { + auto EmitLinkage = [&](MCSymbol *Sym) { + if (GI.hasExternalLinkage() || !MAI->getWeakRefDirective()) + OutStreamer->emitSymbolAttribute(Sym, MCSA_Global); + else if (GI.hasWeakLinkage() || GI.hasLinkOnceLinkage()) + OutStreamer->emitSymbolAttribute(Sym, MCSA_WeakReference); + else + assert(GI.hasLocalLinkage() && "Invalid ifunc linkage"); + }; + + MCSymbol *LazyPointer = TM.getObjFileLowering()->getContext().getOrCreateSymbol( + "_" + GI.getName() + ".lazy_pointer"); + MCSymbol *StubHelper = + TM.getObjFileLowering()->getContext().getOrCreateSymbol( + "_" + GI.getName() + ".stub_helper"); + + OutStreamer->switchSection(OutContext.getObjectFileInfo()->getDataSection()); + + EmitLinkage(LazyPointer); + OutStreamer->emitLabel(LazyPointer); + emitVisibility(LazyPointer, GI.getVisibility()); + OutStreamer->emitValue(MCSymbolRefExpr::create(StubHelper, OutContext), 8); + + OutStreamer->switchSection(OutContext.getObjectFileInfo()->getTextSection()); + + MCSymbol *Stub = getSymbol(&GI); + + EmitLinkage(Stub); + OutStreamer->emitCodeAlignment(Align(4), STI); + OutStreamer->emitLabel(Stub); + emitVisibility(Stub, GI.getVisibility()); + + // adrp x16, lazy_pointer@GOTPAGE + // ldr x16, [x16, lazy_pointer@GOTPAGEOFF] + // ldr x16, [x16] + // br x16 + + { + MCInst Adrp; + Adrp.setOpcode(AArch64::ADRP); + Adrp.addOperand(MCOperand::createReg(AArch64::X16)); + MCOperand SymPage; + MCInstLowering.lowerOperand( + MachineOperand::CreateES(LazyPointer->getName().data() + 1, + AArch64II::MO_GOT | AArch64II::MO_PAGE), + SymPage); + Adrp.addOperand(SymPage); + OutStreamer->emitInstruction(Adrp, *STI); + } + + { + MCInst Ldr; + Ldr.setOpcode(AArch64::LDRXui); + Ldr.addOperand(MCOperand::createReg(AArch64::X16)); + Ldr.addOperand(MCOperand::createReg(AArch64::X16)); + MCOperand SymPageOff; + MCInstLowering.lowerOperand( + MachineOperand::CreateES(LazyPointer->getName().data() + 1, + AArch64II::MO_GOT | AArch64II::MO_PAGEOFF), + SymPageOff); + Ldr.addOperand(SymPageOff); + Ldr.addOperand(MCOperand::createImm(0)); + OutStreamer->emitInstruction(Ldr, *STI); + } + + OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDRXui) + .addReg(AArch64::X16) + .addReg(AArch64::X16) + .addImm(0), *STI); + + OutStreamer->emitInstruction(MCInstBuilder(TM.getTargetTriple().isArm64e() + ? AArch64::BRAAZ + : AArch64::BR) + .addReg(AArch64::X16), + *STI); + + EmitLinkage(StubHelper); + OutStreamer->emitCodeAlignment(Align(4), STI); + OutStreamer->emitLabel(StubHelper); + emitVisibility(StubHelper, GI.getVisibility()); + + // stp fp, lr, [sp, #-16]! + // mov fp, sp + // stp x1, x0, [sp, #-16]! + // stp x3, x2, [sp, #-16]! + // stp x5, x4, [sp, #-16]! + // stp x7, x6, [sp, #-16]! + // stp d1, d0, [sp, #-16]! + // stp d3, d2, [sp, #-16]! + // stp d5, d4, [sp, #-16]! + // stp d7, d6, [sp, #-16]! + // bl _resolver + // adrp x16, lazy_pointer@GOTPAGE + // ldr x16, [x16, lazy_pointer@GOTPAGEOFF] + // str x0, [x16] + // mov x16, x0 + // ldp d7, d6, [sp], #16 + // ldp d5, d4, [sp], #16 + // ldp d3, d2, [sp], #16 + // ldp d1, d0, [sp], #16 + // ldp x7, x6, [sp], #16 + // ldp x5, x4, [sp], #16 + // ldp x3, x2, [sp], #16 + // ldp x1, x0, [sp], #16 + // ldp fp, lr, [sp], #16 + // br x16 + + OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPXpre) + .addReg(AArch64::SP) + .addReg(AArch64::FP) + .addReg(AArch64::LR) + .addReg(AArch64::SP) + .addImm(-2), + *STI); + + OutStreamer->emitInstruction(MCInstBuilder(AArch64::ADDXri) + .addReg(AArch64::FP) + .addReg(AArch64::SP) + .addImm(0) + .addImm(0), + *STI); + + for (int I = 0; I != 4; ++I) + OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPXpre) + .addReg(AArch64::SP) + .addReg(AArch64::X1 + 2 * I) + .addReg(AArch64::X0 + 2 * I) + .addReg(AArch64::SP) + .addImm(-2), + *STI); + + for (int I = 0; I != 4; ++I) + OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPDpre) + .addReg(AArch64::SP) + .addReg(AArch64::D1 + 2 * I) + .addReg(AArch64::D0 + 2 * I) + .addReg(AArch64::SP) + .addImm(-2), + *STI); + + OutStreamer->emitInstruction( + MCInstBuilder(AArch64::BL) + .addOperand(MCOperand::createExpr(lowerConstant(GI.getResolver()))), + *STI); + + { + MCInst Adrp; + Adrp.setOpcode(AArch64::ADRP); + Adrp.addOperand(MCOperand::createReg(AArch64::X16)); + MCOperand SymPage; + MCInstLowering.lowerOperand( + MachineOperand::CreateES(LazyPointer->getName().data() + 1, + AArch64II::MO_GOT | AArch64II::MO_PAGE), + SymPage); + Adrp.addOperand(SymPage); + OutStreamer->emitInstruction(Adrp, *STI); + } + + { + MCInst Ldr; + Ldr.setOpcode(AArch64::LDRXui); + Ldr.addOperand(MCOperand::createReg(AArch64::X16)); + Ldr.addOperand(MCOperand::createReg(AArch64::X16)); + MCOperand SymPageOff; + MCInstLowering.lowerOperand( + MachineOperand::CreateES(LazyPointer->getName().data() + 1, + AArch64II::MO_GOT | AArch64II::MO_PAGEOFF), + SymPageOff); + Ldr.addOperand(SymPageOff); + Ldr.addOperand(MCOperand::createImm(0)); + OutStreamer->emitInstruction(Ldr, *STI); + } + + OutStreamer->emitInstruction(MCInstBuilder(AArch64::STRXui) + .addReg(AArch64::X0) + .addReg(AArch64::X16) + .addImm(0), + *STI); + + OutStreamer->emitInstruction(MCInstBuilder(AArch64::ADDXri) + .addReg(AArch64::X16) + .addReg(AArch64::X0) + .addImm(0) + .addImm(0), + *STI); + + for (int I = 3; I != -1; --I) + OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDPDpost) + .addReg(AArch64::SP) + .addReg(AArch64::D1 + 2 * I) + .addReg(AArch64::D0 + 2 * I) + .addReg(AArch64::SP) + .addImm(2), + *STI); + + for (int I = 3; I != -1; --I) + OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDPXpost) + .addReg(AArch64::SP) + .addReg(AArch64::X1 + 2 * I) + .addReg(AArch64::X0 + 2 * I) + .addReg(AArch64::SP) + .addImm(2), + *STI); + + OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDPXpost) + .addReg(AArch64::SP) + .addReg(AArch64::FP) + .addReg(AArch64::LR) + .addReg(AArch64::SP) + .addImm(2), + *STI); + + OutStreamer->emitInstruction(MCInstBuilder(TM.getTargetTriple().isArm64e() + ? AArch64::BRAAZ + : AArch64::BR) + .addReg(AArch64::X16), + *STI); +} + +void AArch64AsmPrinter::emitGlobalIFunc(Module &M, const GlobalIFunc &GI) { + if (!TM.getTargetTriple().isOSBinFormatMachO()) + return AsmPrinter::emitGlobalIFunc(M, GI); + + switch (PreferredIFuncLowering) { + case IFuncLowering::SymbolResolverAlways: + return emitLinkerSymbolResolver(M, GI); + case IFuncLowering::SymbolResolverNever: + return emitManualSymbolResolver(M, GI); + case IFuncLowering::SymbolResolverIfSupported: + if (GI.hasExternalLinkage() || !MAI->getWeakRefDirective()) + return emitLinkerSymbolResolver(M, GI); + else if (GI.hasWeakLinkage() || GI.hasLinkOnceLinkage()) + // NOTE: non-global .symbol_resolvers are not yet supported by Darwin + // linkers + return emitManualSymbolResolver(M, GI); + else + assert(GI.hasLocalLinkage() && "Invalid ifunc linkage"); + } +} + // Force static initialization. extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeAArch64AsmPrinter() { RegisterAsmPrinter X(getTheAArch64leTarget()); diff --git a/llvm/lib/Target/X86/X86AsmPrinter.cpp b/llvm/lib/Target/X86/X86AsmPrinter.cpp index 73c7450620966..5241aa6e1c0ea 100644 --- a/llvm/lib/Target/X86/X86AsmPrinter.cpp +++ b/llvm/lib/Target/X86/X86AsmPrinter.cpp @@ -530,6 +530,34 @@ void X86AsmPrinter::PrintIntelMemReference(const MachineInstr *MI, O << ']'; } +void X86AsmPrinter::emitGlobalIFunc(Module &M, const GlobalIFunc &GI) { + if (!TM.getTargetTriple().isOSBinFormatMachO()) + return AsmPrinter::emitGlobalIFunc(M, GI); + + OutStreamer->switchSection(OutContext.getObjectFileInfo()->getTextSection()); + + MCSymbol *Name = getSymbol(&GI); + + if (GI.hasExternalLinkage() || !MAI->getWeakRefDirective()) + OutStreamer->emitSymbolAttribute(Name, MCSA_Global); + else if (GI.hasWeakLinkage() || GI.hasLinkOnceLinkage()) + OutStreamer->emitSymbolAttribute(Name, MCSA_WeakReference); + else + assert(GI.hasLocalLinkage() && "Invalid ifunc linkage"); + + OutStreamer->emitCodeAlignment(Align(16), Subtarget); + OutStreamer->emitLabel(Name); + OutStreamer->emitSymbolAttribute(Name, MCSA_SymbolResolver); + emitVisibility(Name, GI.getVisibility()); + + // ld64 does not seem to support aliases of symbol resolvers, so we have to + // tail call the resolver manually. + MCInst JMP; + JMP.setOpcode(X86::JMP_4); + JMP.addOperand(MCOperand::createExpr(lowerConstant(GI.getResolver()))); + OutStreamer->emitInstruction(JMP, *Subtarget); +} + static bool printAsmMRegister(const X86AsmPrinter &P, const MachineOperand &MO, char Mode, raw_ostream &O) { Register Reg = MO.getReg(); diff --git a/llvm/lib/Target/X86/X86AsmPrinter.h b/llvm/lib/Target/X86/X86AsmPrinter.h index c81651cf7f2f0..47f3b7c00c99d 100644 --- a/llvm/lib/Target/X86/X86AsmPrinter.h +++ b/llvm/lib/Target/X86/X86AsmPrinter.h @@ -120,6 +120,7 @@ class LLVM_LIBRARY_VISIBILITY X86AsmPrinter : public AsmPrinter { const char *Modifier); void PrintIntelMemReference(const MachineInstr *MI, unsigned OpNo, raw_ostream &O, const char *Modifier); + void emitGlobalIFunc(Module &M, const GlobalIFunc &GI) override; public: X86AsmPrinter(TargetMachine &TM, std::unique_ptr Streamer); diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/call-lowering-ifunc.ll b/llvm/test/CodeGen/AArch64/GlobalISel/call-lowering-ifunc.ll new file mode 100644 index 0000000000000..8e51845c2faa9 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/GlobalISel/call-lowering-ifunc.ll @@ -0,0 +1,37 @@ +; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py +; RUN: llc -mtriple=aarch64-macho -global-isel -stop-after=irtranslator -verify-machineinstrs -o - %s | FileCheck %s --check-prefixes=MACHO,CHECK +; RUN: llc -mtriple=aarch64-elf -global-isel -stop-after=irtranslator -verify-machineinstrs -o - %s | FileCheck %s --check-prefixes=ELF,CHECK + +@foo_ifunc = ifunc i32 (i32), ptr @foo_resolver + +define internal ptr @foo_resolver() { + ; CHECK-LABEL: name: foo_resolver + ; CHECK: bb.1.entry: + ; CHECK-NEXT: [[C:%[0-9]+]]:_(p0) = G_CONSTANT i64 0 + ; CHECK-NEXT: $x0 = COPY [[C]](p0) + ; CHECK-NEXT: RET_ReallyLR implicit $x0 +entry: + ret ptr null +} + +define void @caller() { + ; MACHO-LABEL: name: caller + ; MACHO: bb.1.entry: + ; MACHO-NEXT: ADJCALLSTACKDOWN 0, 0, implicit-def $sp, implicit $sp + ; MACHO-NEXT: BL @foo_ifunc, csr_aarch64_aapcs, implicit-def $lr, implicit $sp, implicit-def $w0 + ; MACHO-NEXT: ADJCALLSTACKUP 0, 0, implicit-def $sp, implicit $sp + ; MACHO-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $w0 + ; MACHO-NEXT: RET_ReallyLR + ; + ; ELF-LABEL: name: caller + ; ELF: bb.1.entry: + ; ELF-NEXT: [[GV:%[0-9]+]]:gpr64(p0) = G_GLOBAL_VALUE @foo_ifunc + ; ELF-NEXT: ADJCALLSTACKDOWN 0, 0, implicit-def $sp, implicit $sp + ; ELF-NEXT: BLR [[GV]](p0), csr_aarch64_aapcs, implicit-def $lr, implicit $sp, implicit-def $w0 + ; ELF-NEXT: ADJCALLSTACKUP 0, 0, implicit-def $sp, implicit $sp + ; ELF-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $w0 + ; ELF-NEXT: RET_ReallyLR +entry: + %0 = call i32 @foo_ifunc() + ret void +} diff --git a/llvm/test/CodeGen/AArch64/addrsig-macho.ll b/llvm/test/CodeGen/AArch64/addrsig-macho.ll index 360876fccaad3..980b0e7bc4466 100644 --- a/llvm/test/CodeGen/AArch64/addrsig-macho.ll +++ b/llvm/test/CodeGen/AArch64/addrsig-macho.ll @@ -118,8 +118,8 @@ declare void @f3() unnamed_addr @a1 = alias i32, i32* @g1 @a2 = internal local_unnamed_addr alias i32, i32* @g2 -@i1 = ifunc void(), void()* ()* @f1 -@i2 = internal local_unnamed_addr ifunc void(), void()* ()* @f2 +@i1 = external ifunc void(), void()* ()* @f1 +@i2 = external local_unnamed_addr ifunc void(), void()* ()* @f2 declare void @llvm.dbg.value(metadata, metadata, metadata) diff --git a/llvm/test/CodeGen/AArch64/ifunc-asm.ll b/llvm/test/CodeGen/AArch64/ifunc-asm.ll new file mode 100644 index 0000000000000..fbc0f74cee46b --- /dev/null +++ b/llvm/test/CodeGen/AArch64/ifunc-asm.ll @@ -0,0 +1,82 @@ +; RUN: llc -mtriple=arm64-unknown-linux-gnu %s -filetype=asm -o - | FileCheck %s --check-prefixes=ELF +; RUN: llc -mtriple=arm64-apple-darwin %s -filetype=asm -o - -arm64-darwin-ifunc-symbol_resolver=always | FileCheck %s --check-prefixes=MACHO,MACHO-LINKER +; RUN: llc -mtriple=arm64-apple-darwin %s -filetype=asm -o - -arm64-darwin-ifunc-symbol_resolver=if_supported | FileCheck %s --check-prefixes=MACHO,MACHO-DEFAULT +; RUN: llc -mtriple=arm64-apple-darwin %s -filetype=asm -o - -arm64-darwin-ifunc-symbol_resolver=never | FileCheck %s --check-prefixes=MACHO,MACHO-MANUAL +; RUN: llc -mtriple=arm64-apple-darwin %s -filetype=asm -o - | FileCheck %s --check-prefixes=MACHO,MACHO-MANUAL + +define internal ptr @foo_resolver() { +entry: + ret ptr null +} +; ELF: .type foo_resolver,@function +; ELF-NEXT: foo_resolver: + +; MACHO: .p2align 2 +; MACHO-NEXT: _foo_resolver + + +@foo_ifunc = ifunc i32 (i32), ptr @foo_resolver +; ELF: .globl foo_ifunc +; ELF-NEXT: .type foo_ifunc,@gnu_indirect_function +; ELF-NEXT: .set foo_ifunc, foo_resolver + +; MACHO-LINKER: .globl _foo_ifunc +; MACHO-LINKER-NEXT: .p2align 2 +; MACHO-LINKER-NEXT: _foo_ifunc: +; MACHO-LINKER-NEXT: .symbol_resolver _foo_ifunc +; MACHO-LINKER-NEXT: b _foo_resolver + +; MACHO-DEFAULT: .globl _foo_ifunc +; MACHO-DEFAULT-NEXT: .p2align 2 +; MACHO-DEFAULT-NEXT: _foo_ifunc: +; MACHO-DEFAULT-NEXT: .symbol_resolver _foo_ifunc +; MACHO-DEFAULT-NEXT: b _foo_resolver + +; MACHO-MANUAL: .section __DATA,__data +; MACHO-MANUAL-NEXT: .globl _foo_ifunc.lazy_pointer +; MACHO-MANUAL-NEXT: _foo_ifunc.lazy_pointer: +; MACHO-MANUAL-NEXT: .quad _foo_ifunc.stub_helper + +; MACHO-MANUAL: .section __TEXT,__text,regular,pure_instructions +; MACHO-MANUAL-NEXT: .globl _foo_ifunc +; MACHO-MANUAL-NEXT: .p2align 2 +; MACHO-MANUAL-NEXT: _foo_ifunc: +; MACHO-MANUAL-NEXT: adrp x16, _foo_ifunc.lazy_pointer@GOTPAGE +; MACHO-MANUAL-NEXT: ldr x16, [x16, _foo_ifunc.lazy_pointer@GOTPAGEOFF] +; MACHO-MANUAL-NEXT: ldr x16, [x16] +; MACHO-MANUAL-NEXT: br x16 +; MACHO-MANUAL-NEXT: .globl _foo_ifunc.stub_helper +; MACHO-MANUAL-NEXT: .p2align 2 +; MACHO-MANUAL-NEXT: _foo_ifunc.stub_helper: +; MACHO-MANUAL-NEXT: stp x29, x30, [sp, #-16]! +; MACHO-MANUAL-NEXT: mov x29, sp +; MACHO-MANUAL-NEXT: stp x1, x0, [sp, #-16]! +; MACHO-MANUAL-NEXT: stp x3, x2, [sp, #-16]! +; MACHO-MANUAL-NEXT: stp x5, x4, [sp, #-16]! +; MACHO-MANUAL-NEXT: stp x7, x6, [sp, #-16]! +; MACHO-MANUAL-NEXT: stp d1, d0, [sp, #-16]! +; MACHO-MANUAL-NEXT: stp d3, d2, [sp, #-16]! +; MACHO-MANUAL-NEXT: stp d5, d4, [sp, #-16]! +; MACHO-MANUAL-NEXT: stp d7, d6, [sp, #-16]! +; MACHO-MANUAL-NEXT: bl _foo_resolver +; MACHO-MANUAL-NEXT: adrp x16, _foo_ifunc.lazy_pointer@GOTPAGE +; MACHO-MANUAL-NEXT: ldr x16, [x16, _foo_ifunc.lazy_pointer@GOTPAGEOFF] +; MACHO-MANUAL-NEXT: str x0, [x16] +; MACHO-MANUAL-NEXT: add x16, x0, #0 +; MACHO-MANUAL-NEXT: ldp d7, d6, [sp], #16 +; MACHO-MANUAL-NEXT: ldp d5, d4, [sp], #16 +; MACHO-MANUAL-NEXT: ldp d3, d2, [sp], #16 +; MACHO-MANUAL-NEXT: ldp d1, d0, [sp], #16 +; MACHO-MANUAL-NEXT: ldp x7, x6, [sp], #16 +; MACHO-MANUAL-NEXT: ldp x5, x4, [sp], #16 +; MACHO-MANUAL-NEXT: ldp x3, x2, [sp], #16 +; MACHO-MANUAL-NEXT: ldp x1, x0, [sp], #16 +; MACHO-MANUAL-NEXT: ldp x29, x30, [sp], #16 +; MACHO-MANUAL-NEXT: br x16 + + +@weak_ifunc = weak ifunc i32 (i32), ptr @foo_resolver +; ELF: .type weak_ifunc,@gnu_indirect_function +; MACHO-LINKER: .symbol_resolver _weak_ifunc +; MACHO-MANUAL: _weak_ifunc.stub_helper: +; MACHO-DEFEAULT: _weak_ifunc.stub_helper: \ No newline at end of file diff --git a/llvm/test/CodeGen/X86/ifunc-asm.ll b/llvm/test/CodeGen/X86/ifunc-asm.ll index 4b380c8ae3301..76efda7115320 100644 --- a/llvm/test/CodeGen/X86/ifunc-asm.ll +++ b/llvm/test/CodeGen/X86/ifunc-asm.ll @@ -1,14 +1,24 @@ -; RUN: llvm-as < %s -o - | llc -filetype=asm | FileCheck %s +; RUN: llc -filetype=asm -mtriple=x86_64-unknown-linux-gnu %s -o - | FileCheck %s --check-prefixes=ELF +; RUN: llc -filetype=asm -mtriple=x86_64-apple-darwin %s -o - | FileCheck %s --check-prefixes=MACHO -target triple = "x86_64-unknown-linux-gnu" - -define internal ptr @foo_ifunc() { +define internal ptr @foo_resolver() { entry: ret ptr null } -; CHECK: .type foo_ifunc,@function -; CHECK-NEXT: foo_ifunc: +; ELF: .type foo_resolver,@function +; ELF-NEXT: foo_resolver: + +; MACHO: .p2align 4, 0x90 +; MACHO-NEXT: _foo_resolver + + +@foo_ifunc = ifunc i32 (i32), ptr @foo_resolver +; ELF: .globl foo_ifunc +; ELF-NEXT: .type foo_ifunc,@gnu_indirect_function +; ELF-NEXT: .set foo_ifunc, foo_resolver -@foo = ifunc i32 (i32), ptr @foo_ifunc -; CHECK: .type foo,@gnu_indirect_function -; CHECK-NEXT: .set foo, foo_ifunc +; MACHO: .globl _foo_ifunc +; MACHO-NEXT: .p2align 4, 0x90 +; MACHO-NEXT: _foo_ifunc: +; MACHO-NEXT: .symbol_resolver _foo_ifunc +; MACHO-NEXT: jmp _foo_resolver diff --git a/llvm/test/Verifier/ifunc-macho.ll b/llvm/test/Verifier/ifunc-macho.ll new file mode 100644 index 0000000000000..2e2166645983a --- /dev/null +++ b/llvm/test/Verifier/ifunc-macho.ll @@ -0,0 +1,42 @@ +; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s + +target triple = "arm64-apple-ios" + +define ptr @resolver() { + ret ptr null +} + +@g = external global i32 +@inval_objtype = ifunc void (), ptr @g +; CHECK: IFunc must have a Function resolver + +declare ptr @resolver_decl() +@inval_resolver_decl = ifunc void (), ptr @resolver_decl +; CHECK: IFunc resolver must be a definition +; CHECK-NEXT: @inval_resolver_decl + +define available_externally ptr @resolver_linker_decl() { + ret ptr null +} +@inval_resolver_decl2 = ifunc void (), ptr @resolver_linker_decl +; CHECK: IFunc resolver must be a definition +; CHECK-NEXT: @inval_resolver_decl2 + +@ifunc_nonpointer_return_type = ifunc i32 (), ptr @resolver_returns_nonpointer +; CHECK: IFunc resolver must return a pointer +; CHECK-NEXT: ptr @ifunc_nonpointer_return_type + +define i32 @resolver_returns_nonpointer() { + ret i32 0 +} + +@valid_external = ifunc void (), ptr @resolver +; CHECK-NOT: valid_external + +@inval_linkonce = linkonce ifunc void (), ptr @resolver + +@inval_weak = weak ifunc void (), ptr @resolver + +@inval_weak_extern = extern_weak ifunc void (), ptr @resolver + +@inval_private = private ifunc void (), ptr @resolver From de74c62118d9c2c9372a6ba862113f299ac6eb3a Mon Sep 17 00:00:00 2001 From: Jon Roelofs Date: Tue, 28 Nov 2023 11:05:25 -0800 Subject: [PATCH 02/13] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20?= =?UTF-8?q?changes=20introduced=20through=20rebase?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Created using spr 1.3.4 [skip ci] --- llvm/include/llvm/CodeGen/AsmPrinter.h | 1 - llvm/lib/IR/Verifier.cpp | 4 +-- llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp | 25 ++++++++++++------- llvm/lib/Target/X86/X86AsmPrinter.cpp | 2 ++ 4 files changed, 20 insertions(+), 12 deletions(-) diff --git a/llvm/include/llvm/CodeGen/AsmPrinter.h b/llvm/include/llvm/CodeGen/AsmPrinter.h index 48fa6c478464c..07b92871a0f08 100644 --- a/llvm/include/llvm/CodeGen/AsmPrinter.h +++ b/llvm/include/llvm/CodeGen/AsmPrinter.h @@ -887,7 +887,6 @@ class AsmPrinter : public MachineFunctionPass { virtual void emitGlobalIFunc(Module &M, const GlobalIFunc &GI); private: - /// This method decides whether the specified basic block requires a label. bool shouldEmitLabelForBasicBlock(const MachineBasicBlock &MBB) const; diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index 94e76a43bf38d..bd90047a411a6 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -959,7 +959,6 @@ void Verifier::visitGlobalIFunc(const GlobalIFunc &GI) { GlobalIFunc::getResolverFunctionType(GI.getValueType()); Check(ResolverTy == ResolverFuncTy->getPointerTo(GI.getAddressSpace()), "IFunc resolver has incorrect type", &GI); - } void Verifier::visitNamedMDNode(const NamedMDNode &NMD) { @@ -2240,7 +2239,8 @@ void Verifier::verifyFunctionAttrs(FunctionType *FT, AttributeList Attrs, } // Check EVEX512 feature. - if (MaxParameterWidth >= 512 && Attrs.hasFnAttr("target-features") && TT.isX86()) { + if (MaxParameterWidth >= 512 && Attrs.hasFnAttr("target-features") && + TT.isX86()) { StringRef TF = Attrs.getFnAttr("target-features").getValueAsString(); Check(!TF.contains("+avx512f") || !TF.contains("-evex512"), "512-bit vector arguments require 'evex512' for AVX512", V); diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp index 2dab8e126c9ab..f4128332008fb 100644 --- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp +++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp @@ -71,10 +71,15 @@ using namespace llvm; namespace { -enum class IFuncLowering { SymbolResolverIfSupported, SymbolResolverAlways, SymbolResolverNever }; +enum class IFuncLowering { + SymbolResolverIfSupported, + SymbolResolverAlways, + SymbolResolverNever +}; static cl::opt PreferredIFuncLowering( - "arm64-darwin-ifunc-symbol_resolver", cl::init(IFuncLowering::SymbolResolverNever), + "arm64-darwin-ifunc-symbol_resolver", + cl::init(IFuncLowering::SymbolResolverNever), cl::desc("Pick the lowering for ifuncs on darwin platforms"), cl::Hidden, cl::values( clEnumValN( @@ -1853,8 +1858,8 @@ void AArch64AsmPrinter::emitLinkerSymbolResolver(Module &M, OutStreamer->emitSymbolAttribute(Name, MCSA_SymbolResolver); emitVisibility(Name, GI.getVisibility()); - // ld-prime does not seem to support aliases of symbol resolvers, so we have to - // tail call the resolver manually. + // ld-prime does not seem to support aliases of symbol resolvers, so we have + // to tail call the resolver manually. OutStreamer->emitInstruction( MCInstBuilder(AArch64::B) .addOperand(MCOperand::createExpr(lowerConstant(GI.getResolver()))), @@ -1887,8 +1892,9 @@ void AArch64AsmPrinter::emitManualSymbolResolver(Module &M, assert(GI.hasLocalLinkage() && "Invalid ifunc linkage"); }; - MCSymbol *LazyPointer = TM.getObjFileLowering()->getContext().getOrCreateSymbol( - "_" + GI.getName() + ".lazy_pointer"); + MCSymbol *LazyPointer = + TM.getObjFileLowering()->getContext().getOrCreateSymbol( + "_" + GI.getName() + ".lazy_pointer"); MCSymbol *StubHelper = TM.getObjFileLowering()->getContext().getOrCreateSymbol( "_" + GI.getName() + ".stub_helper"); @@ -1943,9 +1949,10 @@ void AArch64AsmPrinter::emitManualSymbolResolver(Module &M, } OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDRXui) - .addReg(AArch64::X16) - .addReg(AArch64::X16) - .addImm(0), *STI); + .addReg(AArch64::X16) + .addReg(AArch64::X16) + .addImm(0), + *STI); OutStreamer->emitInstruction(MCInstBuilder(TM.getTargetTriple().isArm64e() ? AArch64::BRAAZ diff --git a/llvm/lib/Target/X86/X86AsmPrinter.cpp b/llvm/lib/Target/X86/X86AsmPrinter.cpp index 5241aa6e1c0ea..37158900d2404 100644 --- a/llvm/lib/Target/X86/X86AsmPrinter.cpp +++ b/llvm/lib/Target/X86/X86AsmPrinter.cpp @@ -556,6 +556,8 @@ void X86AsmPrinter::emitGlobalIFunc(Module &M, const GlobalIFunc &GI) { JMP.setOpcode(X86::JMP_4); JMP.addOperand(MCOperand::createExpr(lowerConstant(GI.getResolver()))); OutStreamer->emitInstruction(JMP, *Subtarget); + + // FIXME: do the manual .symbol_resolver lowering that we did in AArch64AsmPrinter. } static bool printAsmMRegister(const X86AsmPrinter &P, const MachineOperand &MO, From a34d63cab61b3d7bd327b6a90ee4b9e3ed568e85 Mon Sep 17 00:00:00 2001 From: Jon Roelofs Date: Tue, 28 Nov 2023 14:25:01 -0800 Subject: [PATCH 03/13] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20?= =?UTF-8?q?changes=20introduced=20through=20rebase?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Created using spr 1.3.4 [skip ci] --- llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 48 ++++---- llvm/lib/CodeGen/GlobalISel/CallLowering.cpp | 2 +- llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp | 110 ++++++++++-------- llvm/test/CodeGen/AArch64/addrsig-macho.ll | 17 ++- llvm/test/CodeGen/AArch64/ifunc-asm.ll | 99 ++++++++-------- llvm/test/Verifier/ifunc-macho.ll | 42 ------- 6 files changed, 153 insertions(+), 165 deletions(-) delete mode 100644 llvm/test/Verifier/ifunc-macho.ll diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index 15ff398836803..b4ac0a70e7fde 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -2300,6 +2300,32 @@ bool AsmPrinter::doFinalization(Module &M) { // through user plugins. emitStackMaps(); + // Print aliases in topological order, that is, for each alias a = b, + // b must be printed before a. + // This is because on some targets (e.g. PowerPC) linker expects aliases in + // such an order to generate correct TOC information. + SmallVector AliasStack; + SmallPtrSet AliasVisited; + for (const auto &Alias : M.aliases()) { + if (Alias.hasAvailableExternallyLinkage()) + continue; + for (const GlobalAlias *Cur = &Alias; Cur; + Cur = dyn_cast(Cur->getAliasee())) { + if (!AliasVisited.insert(Cur).second) + break; + AliasStack.push_back(Cur); + } + for (const GlobalAlias *AncestorAlias : llvm::reverse(AliasStack)) + emitGlobalAlias(M, *AncestorAlias); + AliasStack.clear(); + } + + // IFuncs must come before deubginfo in case the backend decides to emit them + // as actual functions, since on MachO targets, we cannot create regular + // sections after DWARF. + for (const auto &IFunc : M.ifuncs()) + emitGlobalIFunc(M, IFunc); + // Finalize debug and EH information. for (const HandlerInfo &HI : Handlers) { NamedRegionTimer T(HI.TimerName, HI.TimerDescription, HI.TimerGroupName, @@ -2339,28 +2365,6 @@ bool AsmPrinter::doFinalization(Module &M) { } } - // Print aliases in topological order, that is, for each alias a = b, - // b must be printed before a. - // This is because on some targets (e.g. PowerPC) linker expects aliases in - // such an order to generate correct TOC information. - SmallVector AliasStack; - SmallPtrSet AliasVisited; - for (const auto &Alias : M.aliases()) { - if (Alias.hasAvailableExternallyLinkage()) - continue; - for (const GlobalAlias *Cur = &Alias; Cur; - Cur = dyn_cast(Cur->getAliasee())) { - if (!AliasVisited.insert(Cur).second) - break; - AliasStack.push_back(Cur); - } - for (const GlobalAlias *AncestorAlias : llvm::reverse(AliasStack)) - emitGlobalAlias(M, *AncestorAlias); - AliasStack.clear(); - } - for (const auto &IFunc : M.ifuncs()) - emitGlobalIFunc(M, IFunc); - GCModuleInfo *MI = getAnalysisIfAvailable(); assert(MI && "AsmPrinter didn't require GCModuleInfo?"); for (GCModuleInfo::iterator I = MI->end(), E = MI->begin(); I != E; ) diff --git a/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp b/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp index e0080b145d4f9..ce736178afc8b 100644 --- a/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp +++ b/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp @@ -147,7 +147,7 @@ bool CallLowering::lowerCall(MachineIRBuilder &MIRBuilder, const CallBase &CB, if (const GlobalIFunc *IF = dyn_cast(CalleeV); IF && MF.getTarget().getTargetTriple().isOSBinFormatMachO()) { // ld64 requires that .symbol_resolvers to be called via a stub, so these - // must always be a diret call. + // must always be a direct call. Info.Callee = MachineOperand::CreateGA(IF, 0); } else if (const Function *F = dyn_cast(CalleeV)) Info.Callee = MachineOperand::CreateGA(F, 0); diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp index f4128332008fb..26b3a14e22b2a 100644 --- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp +++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp @@ -1965,65 +1965,71 @@ void AArch64AsmPrinter::emitManualSymbolResolver(Module &M, OutStreamer->emitLabel(StubHelper); emitVisibility(StubHelper, GI.getVisibility()); - // stp fp, lr, [sp, #-16]! - // mov fp, sp - // stp x1, x0, [sp, #-16]! - // stp x3, x2, [sp, #-16]! - // stp x5, x4, [sp, #-16]! - // stp x7, x6, [sp, #-16]! - // stp d1, d0, [sp, #-16]! - // stp d3, d2, [sp, #-16]! - // stp d5, d4, [sp, #-16]! - // stp d7, d6, [sp, #-16]! + // stp fp, lr, [sp, #-16] + // sub fp, sp, 16 + // stp x1, x0, [sp, #-32] + // stp x3, x2, [sp, #-48] + // stp x5, x4, [sp, #-64] + // stp x7, x6, [sp, #-80] + // stp d1, d0, [sp, #-96] + // stp d3, d2, [sp, #-112] + // stp d5, d4, [sp, #-128] + // stp d7, d6, [sp, #-144] + // sub sp, sp, 144 // bl _resolver // adrp x16, lazy_pointer@GOTPAGE // ldr x16, [x16, lazy_pointer@GOTPAGEOFF] // str x0, [x16] // mov x16, x0 - // ldp d7, d6, [sp], #16 - // ldp d5, d4, [sp], #16 - // ldp d3, d2, [sp], #16 - // ldp d1, d0, [sp], #16 - // ldp x7, x6, [sp], #16 - // ldp x5, x4, [sp], #16 - // ldp x3, x2, [sp], #16 - // ldp x1, x0, [sp], #16 - // ldp fp, lr, [sp], #16 + // add sp, sp, 144 + // ldp d7, d6, [sp, #-144] + // ldp d5, d4, [sp, #-128] + // ldp d3, d2, [sp, #-112] + // ldp d1, d0, [sp, #-96] + // ldp x7, x6, [sp, #-80] + // ldp x5, x4, [sp, #-64] + // ldp x3, x2, [sp, #-48] + // ldp x1, x0, [sp, #-32] + // ldp fp, lr, [sp, #-16] // br x16 - OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPXpre) - .addReg(AArch64::SP) + OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPXi) .addReg(AArch64::FP) .addReg(AArch64::LR) .addReg(AArch64::SP) .addImm(-2), *STI); - OutStreamer->emitInstruction(MCInstBuilder(AArch64::ADDXri) + OutStreamer->emitInstruction(MCInstBuilder(AArch64::SUBXri) .addReg(AArch64::FP) .addReg(AArch64::SP) - .addImm(0) + .addImm(16) .addImm(0), *STI); - for (int I = 0; I != 4; ++I) - OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPXpre) - .addReg(AArch64::SP) - .addReg(AArch64::X1 + 2 * I) - .addReg(AArch64::X0 + 2 * I) + for (int I = 0; I != 8; I += 2) + OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPXi) + .addReg(AArch64::X1 + I) + .addReg(AArch64::X0 + I) .addReg(AArch64::SP) - .addImm(-2), + .addImm(-4 - I), *STI); - for (int I = 0; I != 4; ++I) - OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPDpre) + for (int I = 0; I != 8; I += 2) + OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPDi) + .addReg(AArch64::D1 + I) + .addReg(AArch64::D0 + I) .addReg(AArch64::SP) - .addReg(AArch64::D1 + 2 * I) - .addReg(AArch64::D0 + 2 * I) - .addReg(AArch64::SP) - .addImm(-2), + .addImm(-12 - I), *STI); + OutStreamer->emitInstruction(MCInstBuilder(AArch64::SUBXri) + .addReg(AArch64::SP) + .addReg(AArch64::SP) + .addImm(144) + .addImm(0), + *STI); + OutStreamer->emitInstruction( MCInstBuilder(AArch64::BL) .addOperand(MCOperand::createExpr(lowerConstant(GI.getResolver()))), @@ -2070,30 +2076,34 @@ void AArch64AsmPrinter::emitManualSymbolResolver(Module &M, .addImm(0), *STI); - for (int I = 3; I != -1; --I) - OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDPDpost) - .addReg(AArch64::SP) - .addReg(AArch64::D1 + 2 * I) - .addReg(AArch64::D0 + 2 * I) + OutStreamer->emitInstruction(MCInstBuilder(AArch64::ADDXri) + .addReg(AArch64::SP) + .addReg(AArch64::SP) + .addImm(144) + .addImm(0), + *STI); + + for (int I = 6; I != -2; I -= 2) + OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDPDi) + .addReg(AArch64::D1 + I) + .addReg(AArch64::D0 + I) .addReg(AArch64::SP) - .addImm(2), + .addImm(-12 - I), *STI); - for (int I = 3; I != -1; --I) - OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDPXpost) - .addReg(AArch64::SP) - .addReg(AArch64::X1 + 2 * I) - .addReg(AArch64::X0 + 2 * I) + for (int I = 6; I != -2; I -= 2) + OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDPXi) + .addReg(AArch64::X1 + I) + .addReg(AArch64::X0 + I) .addReg(AArch64::SP) - .addImm(2), + .addImm(-4 - I), *STI); - OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDPXpost) - .addReg(AArch64::SP) + OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDPXi) .addReg(AArch64::FP) .addReg(AArch64::LR) .addReg(AArch64::SP) - .addImm(2), + .addImm(-2), *STI); OutStreamer->emitInstruction(MCInstBuilder(TM.getTargetTriple().isArm64e() diff --git a/llvm/test/CodeGen/AArch64/addrsig-macho.ll b/llvm/test/CodeGen/AArch64/addrsig-macho.ll index 980b0e7bc4466..62bc764e0251b 100644 --- a/llvm/test/CodeGen/AArch64/addrsig-macho.ll +++ b/llvm/test/CodeGen/AArch64/addrsig-macho.ll @@ -3,6 +3,19 @@ ; RUN: llvm-objdump --macho --section-headers %t | FileCheck %s --check-prefix=SECTIONS ; RUN: llvm-objdump --macho --reloc %t | FileCheck %s --check-prefix=RELOCS +; CHECK: .section __DATA,__data +; CHECK: _i1.lazy_pointer: +; CHECK: .section __TEXT,__text,regular,pure_instructions +; CHECK: _i1: +; CHECK: _i1.stub_helper: +; CHECK: .section __DATA,__data +; CHECK: _i2.lazy_pointer: +; CHECK: .section __TEXT,__text,regular,pure_instructions +; CHECK: _i2: +; CHECK: _i2.stub_helper: + +; CHECK: .section __DWARF + ; CHECK: .addrsig{{$}} ; CHECK-NEXT: .addrsig_sym _func03_takeaddr ; CHECK-NEXT: .addrsig_sym _f1 @@ -118,8 +131,8 @@ declare void @f3() unnamed_addr @a1 = alias i32, i32* @g1 @a2 = internal local_unnamed_addr alias i32, i32* @g2 -@i1 = external ifunc void(), void()* ()* @f1 -@i2 = external local_unnamed_addr ifunc void(), void()* ()* @f2 +@i1 = ifunc void(), void()* ()* @f1 +@i2 = internal local_unnamed_addr ifunc void(), void()* ()* @f2 declare void @llvm.dbg.value(metadata, metadata, metadata) diff --git a/llvm/test/CodeGen/AArch64/ifunc-asm.ll b/llvm/test/CodeGen/AArch64/ifunc-asm.ll index fbc0f74cee46b..ede669aa52703 100644 --- a/llvm/test/CodeGen/AArch64/ifunc-asm.ll +++ b/llvm/test/CodeGen/AArch64/ifunc-asm.ll @@ -3,79 +3,82 @@ ; RUN: llc -mtriple=arm64-apple-darwin %s -filetype=asm -o - -arm64-darwin-ifunc-symbol_resolver=if_supported | FileCheck %s --check-prefixes=MACHO,MACHO-DEFAULT ; RUN: llc -mtriple=arm64-apple-darwin %s -filetype=asm -o - -arm64-darwin-ifunc-symbol_resolver=never | FileCheck %s --check-prefixes=MACHO,MACHO-MANUAL ; RUN: llc -mtriple=arm64-apple-darwin %s -filetype=asm -o - | FileCheck %s --check-prefixes=MACHO,MACHO-MANUAL +; RUN: llc -mtriple=arm64-apple-darwin %s -filetype=asm -o - -global-isel | FileCheck %s --check-prefixes=MACHO,MACHO-MANUAL -define internal ptr @foo_resolver() { +define internal ptr @the_resolver() { entry: ret ptr null } -; ELF: .type foo_resolver,@function -; ELF-NEXT: foo_resolver: +; ELF: .type the_resolver,@function +; ELF-NEXT: the_resolver: ; MACHO: .p2align 2 -; MACHO-NEXT: _foo_resolver +; MACHO-NEXT: _the_resolver -@foo_ifunc = ifunc i32 (i32), ptr @foo_resolver -; ELF: .globl foo_ifunc -; ELF-NEXT: .type foo_ifunc,@gnu_indirect_function -; ELF-NEXT: .set foo_ifunc, foo_resolver +@global_ifunc = ifunc i32 (i32), ptr @the_resolver +; ELF: .globl global_ifunc +; ELF-NEXT: .type global_ifunc,@gnu_indirect_function +; ELF-NEXT: .set global_ifunc, the_resolver -; MACHO-LINKER: .globl _foo_ifunc +; MACHO-LINKER: .globl _global_ifunc ; MACHO-LINKER-NEXT: .p2align 2 -; MACHO-LINKER-NEXT: _foo_ifunc: -; MACHO-LINKER-NEXT: .symbol_resolver _foo_ifunc -; MACHO-LINKER-NEXT: b _foo_resolver +; MACHO-LINKER-NEXT: _global_ifunc: +; MACHO-LINKER-NEXT: .symbol_resolver _global_ifunc +; MACHO-LINKER-NEXT: b _the_resolver -; MACHO-DEFAULT: .globl _foo_ifunc +; MACHO-DEFAULT: .globl _global_ifunc ; MACHO-DEFAULT-NEXT: .p2align 2 -; MACHO-DEFAULT-NEXT: _foo_ifunc: -; MACHO-DEFAULT-NEXT: .symbol_resolver _foo_ifunc -; MACHO-DEFAULT-NEXT: b _foo_resolver +; MACHO-DEFAULT-NEXT: _global_ifunc: +; MACHO-DEFAULT-NEXT: .symbol_resolver _global_ifunc +; MACHO-DEFAULT-NEXT: b _the_resolver ; MACHO-MANUAL: .section __DATA,__data -; MACHO-MANUAL-NEXT: .globl _foo_ifunc.lazy_pointer -; MACHO-MANUAL-NEXT: _foo_ifunc.lazy_pointer: -; MACHO-MANUAL-NEXT: .quad _foo_ifunc.stub_helper +; MACHO-MANUAL-NEXT: .globl _global_ifunc.lazy_pointer +; MACHO-MANUAL-NEXT: _global_ifunc.lazy_pointer: +; MACHO-MANUAL-NEXT: .quad _global_ifunc.stub_helper ; MACHO-MANUAL: .section __TEXT,__text,regular,pure_instructions -; MACHO-MANUAL-NEXT: .globl _foo_ifunc +; MACHO-MANUAL-NEXT: .globl _global_ifunc ; MACHO-MANUAL-NEXT: .p2align 2 -; MACHO-MANUAL-NEXT: _foo_ifunc: -; MACHO-MANUAL-NEXT: adrp x16, _foo_ifunc.lazy_pointer@GOTPAGE -; MACHO-MANUAL-NEXT: ldr x16, [x16, _foo_ifunc.lazy_pointer@GOTPAGEOFF] +; MACHO-MANUAL-NEXT: _global_ifunc: +; MACHO-MANUAL-NEXT: adrp x16, _global_ifunc.lazy_pointer@GOTPAGE +; MACHO-MANUAL-NEXT: ldr x16, [x16, _global_ifunc.lazy_pointer@GOTPAGEOFF] ; MACHO-MANUAL-NEXT: ldr x16, [x16] ; MACHO-MANUAL-NEXT: br x16 -; MACHO-MANUAL-NEXT: .globl _foo_ifunc.stub_helper +; MACHO-MANUAL-NEXT: .globl _global_ifunc.stub_helper ; MACHO-MANUAL-NEXT: .p2align 2 -; MACHO-MANUAL-NEXT: _foo_ifunc.stub_helper: -; MACHO-MANUAL-NEXT: stp x29, x30, [sp, #-16]! -; MACHO-MANUAL-NEXT: mov x29, sp -; MACHO-MANUAL-NEXT: stp x1, x0, [sp, #-16]! -; MACHO-MANUAL-NEXT: stp x3, x2, [sp, #-16]! -; MACHO-MANUAL-NEXT: stp x5, x4, [sp, #-16]! -; MACHO-MANUAL-NEXT: stp x7, x6, [sp, #-16]! -; MACHO-MANUAL-NEXT: stp d1, d0, [sp, #-16]! -; MACHO-MANUAL-NEXT: stp d3, d2, [sp, #-16]! -; MACHO-MANUAL-NEXT: stp d5, d4, [sp, #-16]! -; MACHO-MANUAL-NEXT: stp d7, d6, [sp, #-16]! -; MACHO-MANUAL-NEXT: bl _foo_resolver -; MACHO-MANUAL-NEXT: adrp x16, _foo_ifunc.lazy_pointer@GOTPAGE -; MACHO-MANUAL-NEXT: ldr x16, [x16, _foo_ifunc.lazy_pointer@GOTPAGEOFF] +; MACHO-MANUAL-NEXT: _global_ifunc.stub_helper: +; MACHO-MANUAL-NEXT: stp x29, x30, [sp, #-16] +; MACHO-MANUAL-NEXT: sub x29, sp, #16 +; MACHO-MANUAL-NEXT: stp x1, x0, [sp, #-32] +; MACHO-MANUAL-NEXT: stp x3, x2, [sp, #-48] +; MACHO-MANUAL-NEXT: stp x5, x4, [sp, #-64] +; MACHO-MANUAL-NEXT: stp x7, x6, [sp, #-80] +; MACHO-MANUAL-NEXT: stp d1, d0, [sp, #-96] +; MACHO-MANUAL-NEXT: stp d3, d2, [sp, #-112] +; MACHO-MANUAL-NEXT: stp d5, d4, [sp, #-128] +; MACHO-MANUAL-NEXT: stp d7, d6, [sp, #-144] +; MACHO-MANUAL-NEXT: sub sp, sp, #144 +; MACHO-MANUAL-NEXT: bl _the_resolver +; MACHO-MANUAL-NEXT: adrp x16, _global_ifunc.lazy_pointer@GOTPAGE +; MACHO-MANUAL-NEXT: ldr x16, [x16, _global_ifunc.lazy_pointer@GOTPAGEOFF] ; MACHO-MANUAL-NEXT: str x0, [x16] ; MACHO-MANUAL-NEXT: add x16, x0, #0 -; MACHO-MANUAL-NEXT: ldp d7, d6, [sp], #16 -; MACHO-MANUAL-NEXT: ldp d5, d4, [sp], #16 -; MACHO-MANUAL-NEXT: ldp d3, d2, [sp], #16 -; MACHO-MANUAL-NEXT: ldp d1, d0, [sp], #16 -; MACHO-MANUAL-NEXT: ldp x7, x6, [sp], #16 -; MACHO-MANUAL-NEXT: ldp x5, x4, [sp], #16 -; MACHO-MANUAL-NEXT: ldp x3, x2, [sp], #16 -; MACHO-MANUAL-NEXT: ldp x1, x0, [sp], #16 -; MACHO-MANUAL-NEXT: ldp x29, x30, [sp], #16 +; MACHO-MANUAL-NEXT: add sp, sp, #144 +; MACHO-MANUAL-NEXT: ldp d7, d6, [sp, #-144] +; MACHO-MANUAL-NEXT: ldp d5, d4, [sp, #-128] +; MACHO-MANUAL-NEXT: ldp d3, d2, [sp, #-112] +; MACHO-MANUAL-NEXT: ldp d1, d0, [sp, #-96] +; MACHO-MANUAL-NEXT: ldp x7, x6, [sp, #-80] +; MACHO-MANUAL-NEXT: ldp x5, x4, [sp, #-64] +; MACHO-MANUAL-NEXT: ldp x3, x2, [sp, #-48] +; MACHO-MANUAL-NEXT: ldp x1, x0, [sp, #-32] +; MACHO-MANUAL-NEXT: ldp x29, x30, [sp, #-16] ; MACHO-MANUAL-NEXT: br x16 -@weak_ifunc = weak ifunc i32 (i32), ptr @foo_resolver +@weak_ifunc = weak ifunc i32 (i32), ptr @the_resolver ; ELF: .type weak_ifunc,@gnu_indirect_function ; MACHO-LINKER: .symbol_resolver _weak_ifunc ; MACHO-MANUAL: _weak_ifunc.stub_helper: diff --git a/llvm/test/Verifier/ifunc-macho.ll b/llvm/test/Verifier/ifunc-macho.ll deleted file mode 100644 index 2e2166645983a..0000000000000 --- a/llvm/test/Verifier/ifunc-macho.ll +++ /dev/null @@ -1,42 +0,0 @@ -; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s - -target triple = "arm64-apple-ios" - -define ptr @resolver() { - ret ptr null -} - -@g = external global i32 -@inval_objtype = ifunc void (), ptr @g -; CHECK: IFunc must have a Function resolver - -declare ptr @resolver_decl() -@inval_resolver_decl = ifunc void (), ptr @resolver_decl -; CHECK: IFunc resolver must be a definition -; CHECK-NEXT: @inval_resolver_decl - -define available_externally ptr @resolver_linker_decl() { - ret ptr null -} -@inval_resolver_decl2 = ifunc void (), ptr @resolver_linker_decl -; CHECK: IFunc resolver must be a definition -; CHECK-NEXT: @inval_resolver_decl2 - -@ifunc_nonpointer_return_type = ifunc i32 (), ptr @resolver_returns_nonpointer -; CHECK: IFunc resolver must return a pointer -; CHECK-NEXT: ptr @ifunc_nonpointer_return_type - -define i32 @resolver_returns_nonpointer() { - ret i32 0 -} - -@valid_external = ifunc void (), ptr @resolver -; CHECK-NOT: valid_external - -@inval_linkonce = linkonce ifunc void (), ptr @resolver - -@inval_weak = weak ifunc void (), ptr @resolver - -@inval_weak_extern = extern_weak ifunc void (), ptr @resolver - -@inval_private = private ifunc void (), ptr @resolver From e5f65ace88f017fad809e43f0146ddefc2d6160f Mon Sep 17 00:00:00 2001 From: Jon Roelofs Date: Wed, 29 Nov 2023 08:23:38 -0800 Subject: [PATCH 04/13] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20?= =?UTF-8?q?changes=20introduced=20through=20rebase?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Created using spr 1.3.4 [skip ci] --- llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp | 72 +++++----- llvm/lib/Target/X86/X86AsmPrinter.cpp | 124 +++++++++++++++--- llvm/test/CodeGen/X86/ifunc-asm.ll | 48 +++++-- 3 files changed, 178 insertions(+), 66 deletions(-) diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp index 26b3a14e22b2a..1b5b7c556c79f 100644 --- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp +++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp @@ -1901,6 +1901,9 @@ void AArch64AsmPrinter::emitManualSymbolResolver(Module &M, OutStreamer->switchSection(OutContext.getObjectFileInfo()->getDataSection()); + // _ifunc.lazy_pointer: + // .quad _ifunc.stub_helper + EmitLinkage(LazyPointer); OutStreamer->emitLabel(LazyPointer); emitVisibility(LazyPointer, GI.getVisibility()); @@ -1908,18 +1911,18 @@ void AArch64AsmPrinter::emitManualSymbolResolver(Module &M, OutStreamer->switchSection(OutContext.getObjectFileInfo()->getTextSection()); - MCSymbol *Stub = getSymbol(&GI); + // _ifunc: + // adrp x16, lazy_pointer@GOTPAGE + // ldr x16, [x16, lazy_pointer@GOTPAGEOFF] + // ldr x16, [x16] + // br x16 + MCSymbol *Stub = getSymbol(&GI); EmitLinkage(Stub); OutStreamer->emitCodeAlignment(Align(4), STI); OutStreamer->emitLabel(Stub); emitVisibility(Stub, GI.getVisibility()); - // adrp x16, lazy_pointer@GOTPAGE - // ldr x16, [x16, lazy_pointer@GOTPAGEOFF] - // ldr x16, [x16] - // br x16 - { MCInst Adrp; Adrp.setOpcode(AArch64::ADRP); @@ -1960,39 +1963,40 @@ void AArch64AsmPrinter::emitManualSymbolResolver(Module &M, .addReg(AArch64::X16), *STI); + // _ifunc.stub_helper: + // stp fp, lr, [sp, #-16] + // sub fp, sp, 16 + // stp x1, x0, [sp, #-32] + // stp x3, x2, [sp, #-48] + // stp x5, x4, [sp, #-64] + // stp x7, x6, [sp, #-80] + // stp d1, d0, [sp, #-96] + // stp d3, d2, [sp, #-112] + // stp d5, d4, [sp, #-128] + // stp d7, d6, [sp, #-144] + // sub sp, sp, 144 + // bl _resolver + // adrp x16, lazy_pointer@GOTPAGE + // ldr x16, [x16, lazy_pointer@GOTPAGEOFF] + // str x0, [x16] + // mov x16, x0 + // add sp, sp, 144 + // ldp d7, d6, [sp, #-144] + // ldp d5, d4, [sp, #-128] + // ldp d3, d2, [sp, #-112] + // ldp d1, d0, [sp, #-96] + // ldp x7, x6, [sp, #-80] + // ldp x5, x4, [sp, #-64] + // ldp x3, x2, [sp, #-48] + // ldp x1, x0, [sp, #-32] + // ldp fp, lr, [sp, #-16] + // br x16 + EmitLinkage(StubHelper); OutStreamer->emitCodeAlignment(Align(4), STI); OutStreamer->emitLabel(StubHelper); emitVisibility(StubHelper, GI.getVisibility()); - // stp fp, lr, [sp, #-16] - // sub fp, sp, 16 - // stp x1, x0, [sp, #-32] - // stp x3, x2, [sp, #-48] - // stp x5, x4, [sp, #-64] - // stp x7, x6, [sp, #-80] - // stp d1, d0, [sp, #-96] - // stp d3, d2, [sp, #-112] - // stp d5, d4, [sp, #-128] - // stp d7, d6, [sp, #-144] - // sub sp, sp, 144 - // bl _resolver - // adrp x16, lazy_pointer@GOTPAGE - // ldr x16, [x16, lazy_pointer@GOTPAGEOFF] - // str x0, [x16] - // mov x16, x0 - // add sp, sp, 144 - // ldp d7, d6, [sp, #-144] - // ldp d5, d4, [sp, #-128] - // ldp d3, d2, [sp, #-112] - // ldp d1, d0, [sp, #-96] - // ldp x7, x6, [sp, #-80] - // ldp x5, x4, [sp, #-64] - // ldp x3, x2, [sp, #-48] - // ldp x1, x0, [sp, #-32] - // ldp fp, lr, [sp, #-16] - // br x16 - OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPXi) .addReg(AArch64::FP) .addReg(AArch64::LR) diff --git a/llvm/lib/Target/X86/X86AsmPrinter.cpp b/llvm/lib/Target/X86/X86AsmPrinter.cpp index 37158900d2404..b0f4b9d984372 100644 --- a/llvm/lib/Target/X86/X86AsmPrinter.cpp +++ b/llvm/lib/Target/X86/X86AsmPrinter.cpp @@ -14,6 +14,7 @@ #include "X86AsmPrinter.h" #include "MCTargetDesc/X86ATTInstPrinter.h" #include "MCTargetDesc/X86BaseInfo.h" +#include "MCTargetDesc/X86MCTargetDesc.h" #include "MCTargetDesc/X86TargetStreamer.h" #include "TargetInfo/X86TargetInfo.h" #include "X86InstrInfo.h" @@ -34,6 +35,7 @@ #include "llvm/MC/MCCodeEmitter.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" #include "llvm/MC/MCInstBuilder.h" #include "llvm/MC/MCSectionCOFF.h" #include "llvm/MC/MCSectionELF.h" @@ -534,30 +536,112 @@ void X86AsmPrinter::emitGlobalIFunc(Module &M, const GlobalIFunc &GI) { if (!TM.getTargetTriple().isOSBinFormatMachO()) return AsmPrinter::emitGlobalIFunc(M, GI); - OutStreamer->switchSection(OutContext.getObjectFileInfo()->getTextSection()); + auto EmitLinkage = [&](MCSymbol *Sym) { + if (GI.hasExternalLinkage() || !MAI->getWeakRefDirective()) + OutStreamer->emitSymbolAttribute(Sym, MCSA_Global); + else if (GI.hasWeakLinkage() || GI.hasLinkOnceLinkage()) + OutStreamer->emitSymbolAttribute(Sym, MCSA_WeakReference); + else + assert(GI.hasLocalLinkage() && "Invalid ifunc linkage"); + }; - MCSymbol *Name = getSymbol(&GI); + MCSymbol *LazyPointer = + TM.getObjFileLowering()->getContext().getOrCreateSymbol( + "_" + GI.getName() + ".lazy_pointer"); + MCSymbol *StubHelper = + TM.getObjFileLowering()->getContext().getOrCreateSymbol( + "_" + GI.getName() + ".stub_helper"); - if (GI.hasExternalLinkage() || !MAI->getWeakRefDirective()) - OutStreamer->emitSymbolAttribute(Name, MCSA_Global); - else if (GI.hasWeakLinkage() || GI.hasLinkOnceLinkage()) - OutStreamer->emitSymbolAttribute(Name, MCSA_WeakReference); - else - assert(GI.hasLocalLinkage() && "Invalid ifunc linkage"); + OutStreamer->switchSection(OutContext.getObjectFileInfo()->getDataSection()); + + // _ifunc.lazy_pointer: + // .quad _ifunc.stub_helper + EmitLinkage(LazyPointer); + OutStreamer->emitLabel(LazyPointer); + emitVisibility(LazyPointer, GI.getVisibility()); + OutStreamer->emitValue(MCSymbolRefExpr::create(StubHelper, OutContext), 8); + + OutStreamer->switchSection(OutContext.getObjectFileInfo()->getTextSection()); + + // _ifunc: + // jmpq *lazy_pointer(%rip) + + MCSymbol *Stub = getSymbol(&GI); + EmitLinkage(Stub); + OutStreamer->emitCodeAlignment(Align(16), Subtarget); + OutStreamer->emitLabel(Stub); + emitVisibility(Stub, GI.getVisibility()); + + OutStreamer->emitInstruction( + MCInstBuilder(X86::JMP32m) + .addReg(X86::RIP) + .addImm(1) + .addReg(0) + .addOperand(MCOperand::createExpr( + MCSymbolRefExpr::create(LazyPointer, OutContext))) + .addReg(0), + *Subtarget); + + // _ifunc.stub_helper: + // push %rax + // push %rdi + // push %rsi + // push %rdx + // push %rcx + // push %r8 + // push %r9 + // callq foo + // movq %rax,lazy_pointer(%rip) + // pop %r9 + // pop %r8 + // pop %rcx + // pop %rdx + // pop %rsi + // pop %rdi + // pop %rax + // jmpq *lazy_pointer(%rip) + + EmitLinkage(StubHelper); OutStreamer->emitCodeAlignment(Align(16), Subtarget); - OutStreamer->emitLabel(Name); - OutStreamer->emitSymbolAttribute(Name, MCSA_SymbolResolver); - emitVisibility(Name, GI.getVisibility()); - - // ld64 does not seem to support aliases of symbol resolvers, so we have to - // tail call the resolver manually. - MCInst JMP; - JMP.setOpcode(X86::JMP_4); - JMP.addOperand(MCOperand::createExpr(lowerConstant(GI.getResolver()))); - OutStreamer->emitInstruction(JMP, *Subtarget); - - // FIXME: do the manual .symbol_resolver lowering that we did in AArch64AsmPrinter. + OutStreamer->emitLabel(StubHelper); + emitVisibility(StubHelper, GI.getVisibility()); + + for (int Reg : + {X86::RAX, X86::RDI, X86::RSI, X86::RDX, X86::RCX, X86::R8, X86::R9}) + OutStreamer->emitInstruction(MCInstBuilder(X86::PUSH64r).addReg(Reg), + *Subtarget); + + OutStreamer->emitInstruction( + MCInstBuilder(X86::CALL64pcrel32) + .addOperand(MCOperand::createExpr(lowerConstant(GI.getResolver()))), + *Subtarget); + + OutStreamer->emitInstruction( + MCInstBuilder(X86::MOV64mr) + .addReg(X86::RIP) + .addImm(1) + .addReg(0) + .addOperand(MCOperand::createExpr( + MCSymbolRefExpr::create(LazyPointer, OutContext))) + .addReg(0) + .addReg(X86::RAX), + *Subtarget); + + for (int Reg : + {X86::R9, X86::R8, X86::RCX, X86::RDX, X86::RSI, X86::RDI, X86::RAX}) + OutStreamer->emitInstruction(MCInstBuilder(X86::POP64r).addReg(Reg), + *Subtarget); + + OutStreamer->emitInstruction( + MCInstBuilder(X86::JMP32m) + .addReg(X86::RIP) + .addImm(1) + .addReg(0) + .addOperand(MCOperand::createExpr( + MCSymbolRefExpr::create(LazyPointer, OutContext))) + .addReg(0), + *Subtarget); } static bool printAsmMRegister(const X86AsmPrinter &P, const MachineOperand &MO, diff --git a/llvm/test/CodeGen/X86/ifunc-asm.ll b/llvm/test/CodeGen/X86/ifunc-asm.ll index 76efda7115320..0f66febbe95b2 100644 --- a/llvm/test/CodeGen/X86/ifunc-asm.ll +++ b/llvm/test/CodeGen/X86/ifunc-asm.ll @@ -5,20 +5,44 @@ define internal ptr @foo_resolver() { entry: ret ptr null } -; ELF: .type foo_resolver,@function -; ELF-NEXT: foo_resolver: +; ELF: .type foo_resolver,@function +; ELF-NEXT: foo_resolver: -; MACHO: .p2align 4, 0x90 -; MACHO-NEXT: _foo_resolver +; MACHO: .p2align 4, 0x90 +; MACHO-NEXT: _foo_resolver @foo_ifunc = ifunc i32 (i32), ptr @foo_resolver -; ELF: .globl foo_ifunc -; ELF-NEXT: .type foo_ifunc,@gnu_indirect_function -; ELF-NEXT: .set foo_ifunc, foo_resolver +; ELF: .globl foo_ifunc +; ELF-NEXT: .type foo_ifunc,@gnu_indirect_function +; ELF-NEXT: .set foo_ifunc, foo_resolver -; MACHO: .globl _foo_ifunc -; MACHO-NEXT: .p2align 4, 0x90 -; MACHO-NEXT: _foo_ifunc: -; MACHO-NEXT: .symbol_resolver _foo_ifunc -; MACHO-NEXT: jmp _foo_resolver +; MACHO: .section __DATA,__data +; MACHO-NEXT: .globl _foo_ifunc.lazy_pointer +; MACHO-NEXT: _foo_ifunc.lazy_pointer: +; MACHO-NEXT: .quad _foo_ifunc.stub_helper +; MACHO-NEXT: .section __TEXT,__text,regular,pure_instructions +; MACHO-NEXT: .globl _foo_ifunc +; MACHO-NEXT: .p2align 4, 0x90 +; MACHO-NEXT: _foo_ifunc: +; MACHO-NEXT: jmpl *_foo_ifunc.lazy_pointer(%rip) +; MACHO-NEXT: .globl _foo_ifunc.stub_helper +; MACHO-NEXT: .p2align 4, 0x90 +; MACHO-NEXT: _foo_ifunc.stub_helper: +; MACHO-NEXT: pushq %rax +; MACHO-NEXT: pushq %rdi +; MACHO-NEXT: pushq %rsi +; MACHO-NEXT: pushq %rdx +; MACHO-NEXT: pushq %rcx +; MACHO-NEXT: pushq %r8 +; MACHO-NEXT: pushq %r9 +; MACHO-NEXT: callq _foo_resolver +; MACHO-NEXT: movq %rax, _foo_ifunc.lazy_pointer(%rip) +; MACHO-NEXT: popq %r9 +; MACHO-NEXT: popq %r8 +; MACHO-NEXT: popq %rcx +; MACHO-NEXT: popq %rdx +; MACHO-NEXT: popq %rsi +; MACHO-NEXT: popq %rdi +; MACHO-NEXT: popq %rax +; MACHO-NEXT: jmpl *_foo_ifunc.lazy_pointer(%rip) \ No newline at end of file From eafbe063de80818d4a9e2714bf317fa759550f39 Mon Sep 17 00:00:00 2001 From: Jon Roelofs Date: Wed, 29 Nov 2023 12:23:57 -0800 Subject: [PATCH 05/13] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20?= =?UTF-8?q?changes=20introduced=20through=20rebase?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Created using spr 1.3.4 [skip ci] --- clang/test/CodeGen/attr-cpuspecific.c | 1 + clang/test/CodeGen/attr-ifunc.c | 20 ++ clang/test/CodeGen/attr-ifunc.cpp | 4 + clang/test/CodeGen/attr-target-clones.c | 80 +++++ clang/test/CodeGen/attr-target-mv-func-ptrs.c | 1 + clang/test/CodeGen/attr-target-mv.c | 299 +++++++++--------- clang/test/CodeGenCXX/attr-cpuspecific.cpp | 1 + clang/test/CodeGenCXX/attr-target-clones.cpp | 82 ++--- .../CodeGenCXX/attr-target-mv-diff-ns.cpp | 65 ++-- .../CodeGenCXX/attr-target-mv-func-ptrs.cpp | 1 + .../CodeGenCXX/attr-target-mv-inalloca.cpp | 5 + .../attr-target-mv-member-funcs.cpp | 139 ++++---- .../CodeGenCXX/attr-target-mv-modules.cpp | 1 + .../attr-target-mv-out-of-line-defs.cpp | 38 ++- .../CodeGenCXX/attr-target-mv-overloads.cpp | 65 ++-- .../CodeGenCXX/externc-ifunc-resolver.cpp | 2 + clang/test/SemaCXX/externc-ifunc-resolver.cpp | 4 + 17 files changed, 485 insertions(+), 323 deletions(-) diff --git a/clang/test/CodeGen/attr-cpuspecific.c b/clang/test/CodeGen/attr-cpuspecific.c index 9150597e8c5a8..5baa271b5240f 100644 --- a/clang/test/CodeGen/attr-cpuspecific.c +++ b/clang/test/CodeGen/attr-cpuspecific.c @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK,LINUX +// RUN: %clang_cc1 -triple x86_64-apple-macosx -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK,LINUX // RUN: %clang_cc1 -triple x86_64-windows-pc -fms-compatibility -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK,WINDOWS #ifdef _WIN64 diff --git a/clang/test/CodeGen/attr-ifunc.c b/clang/test/CodeGen/attr-ifunc.c index 4f8fe13530fdb..2ad41edf20dfa 100644 --- a/clang/test/CodeGen/attr-ifunc.c +++ b/clang/test/CodeGen/attr-ifunc.c @@ -1,6 +1,7 @@ // RUN: %clang_cc1 -triple x86_64-windows -fsyntax-only -verify %s // RUN: %clang_cc1 -triple x86_64-linux -fsyntax-only -verify -emit-llvm-only -DCHECK_ALIASES %s // RUN: %clang_cc1 -triple x86_64-linux -fsyntax-only -verify -emit-llvm-only %s +// RUN: %clang_cc1 -triple x86_64-apple-macosx -fsyntax-only -verify -emit-llvm-only %s #if defined(_WIN32) void foo(void) {} @@ -36,6 +37,25 @@ void *f6_resolver(void) __attribute__((ifunc("f6_resolver_resolver"))); void f6(void) __attribute__((ifunc("f6_resolver"))); // expected-error@-1 {{ifunc must point to a defined function}} +#elif defined(__APPLE__) + +// NOTE: aliases are not supported on Darwin, so the above tests are not relevant. + +#define STR2(X) #X +#define STR(X) STR2(X) +#define PREFIX STR(__USER_LABEL_PREFIX__) + +void f1a(void) __asm("f1"); +void f1a(void) {} +// expected-note@-1 {{previous definition is here}} +void f1(void) __attribute__((ifunc(PREFIX "f1_ifunc"))) __asm("f1"); +// expected-error@-1 {{definition with same mangled name 'f1' as another definition}} +void *f1_ifunc(void) { return 0; } + +void *f6_ifunc(int i); +void __attribute__((ifunc(PREFIX "f6_ifunc"))) f6(void) {} +// expected-error@-1 {{definition 'f6' cannot also be an ifunc}} + #else void f1a(void) __asm("f1"); void f1a(void) {} diff --git a/clang/test/CodeGen/attr-ifunc.cpp b/clang/test/CodeGen/attr-ifunc.cpp index 5b5b2c14b4074..b6e342df46eb5 100644 --- a/clang/test/CodeGen/attr-ifunc.cpp +++ b/clang/test/CodeGen/attr-ifunc.cpp @@ -1,5 +1,9 @@ // RUN: %clang_cc1 -triple x86_64-linux -fsyntax-only -verify -emit-llvm-only %s +// RUN: %clang_cc1 -triple x86_64-apple-macosx -fsyntax-only -verify -emit-llvm-only %s +// RUN: %clang_cc1 -triple arm64-apple-macosx -fsyntax-only -verify -emit-llvm-only %s // RUN: not %clang_cc1 -triple x86_64-linux -emit-llvm-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s +// RUN: not %clang_cc1 -triple x86_64-apple-macosx -emit-llvm-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s +// RUN: not %clang_cc1 -triple arm64-apple-macosx -emit-llvm-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s void *f1_ifunc(void) { return nullptr; } void f1(void) __attribute__((ifunc("f1_ifunc"))); diff --git a/clang/test/CodeGen/attr-target-clones.c b/clang/test/CodeGen/attr-target-clones.c index 98ffea40f56d8..32d4d6f32f68e 100644 --- a/clang/test/CodeGen/attr-target-clones.c +++ b/clang/test/CodeGen/attr-target-clones.c @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefixes=LINUX,CHECK +// RUN: %clang_cc1 -triple x86_64-apple-macosx -emit-llvm %s -o - | FileCheck %s --check-prefixes=DARWIN,CHECK // RUN: %clang_cc1 -triple x86_64-windows-pc -emit-llvm %s -o - | FileCheck %s --check-prefixes=WINDOWS,CHECK // LINUX: $foo.resolver = comdat any @@ -7,6 +8,8 @@ // LINUX: $foo_inline.resolver = comdat any // LINUX: $foo_inline2.resolver = comdat any +// DARWIN-NOT: comdat any + // WINDOWS: $foo = comdat any // WINDOWS: $foo_dupes = comdat any // WINDOWS: $unused = comdat any @@ -16,6 +19,9 @@ // LINUX: @__cpu_model = external dso_local global { i32, i32, i32, [1 x i32] } // LINUX: @__cpu_features2 = external dso_local global [3 x i32] +// DARWIN: @__cpu_model = external dso_local global { i32, i32, i32, [1 x i32] } +// DARWIN: @__cpu_features2 = external dso_local global [3 x i32] + // LINUX: @internal.ifunc = internal ifunc i32 (), ptr @internal.resolver // LINUX: @foo.ifunc = weak_odr ifunc i32 (), ptr @foo.resolver // LINUX: @foo_dupes.ifunc = weak_odr ifunc void (), ptr @foo_dupes.resolver @@ -28,6 +34,7 @@ static int __attribute__((target_clones("sse4.2, default"))) internal(void) { re int use(void) { return internal(); } /// Internal linkage resolvers do not use comdat. // LINUX: define internal ptr @internal.resolver() { +// DARWIN: define internal ptr @internal.resolver() { // WINDOWS: define internal i32 @internal() { int __attribute__((target_clones("sse4.2, default"))) foo(void) { return 0; } @@ -37,6 +44,12 @@ int __attribute__((target_clones("sse4.2, default"))) foo(void) { return 0; } // LINUX: ret ptr @foo.sse4.2.0 // LINUX: ret ptr @foo.default.1 +// DARWIN: define {{.*}}i32 @foo.sse4.2.0() +// DARWIN: define {{.*}}i32 @foo.default.1() +// DARWIN: define weak_odr ptr @foo.resolver() { +// DARWIN: ret ptr @foo.sse4.2.0 +// DARWIN: ret ptr @foo.default.1 + // WINDOWS: define dso_local i32 @foo.sse4.2.0() // WINDOWS: define dso_local i32 @foo.default.1() // WINDOWS: define weak_odr dso_local i32 @foo() comdat @@ -50,6 +63,12 @@ __attribute__((target_clones("default,default ,sse4.2"))) void foo_dupes(void) { // LINUX: ret ptr @foo_dupes.sse4.2.0 // LINUX: ret ptr @foo_dupes.default.1 +// DARWIN: define {{.*}}void @foo_dupes.default.1() +// DARWIN: define {{.*}}void @foo_dupes.sse4.2.0() +// DARWIN: define weak_odr ptr @foo_dupes.resolver() { +// DARWIN: ret ptr @foo_dupes.sse4.2.0 +// DARWIN: ret ptr @foo_dupes.default.1 + // WINDOWS: define dso_local void @foo_dupes.default.1() // WINDOWS: define dso_local void @foo_dupes.sse4.2.0() // WINDOWS: define weak_odr dso_local void @foo_dupes() comdat @@ -58,17 +77,21 @@ __attribute__((target_clones("default,default ,sse4.2"))) void foo_dupes(void) { void bar2(void) { // LINUX: define {{.*}}void @bar2() + // DARWIN: define {{.*}}void @bar2() // WINDOWS: define dso_local void @bar2() foo_dupes(); // LINUX: call void @foo_dupes.ifunc() + // DARWIN: call void @foo_dupes.ifunc() // WINDOWS: call void @foo_dupes() } int bar(void) { // LINUX: define {{.*}}i32 @bar() #[[DEF:[0-9]+]] + // DARWIN: define {{.*}}i32 @bar() #[[DEF:[0-9]+]] // WINDOWS: define dso_local i32 @bar() #[[DEF:[0-9]+]] return foo(); // LINUX: call i32 @foo.ifunc() + // DARWIN: call i32 @foo.ifunc() // WINDOWS: call i32 @foo() } @@ -79,6 +102,12 @@ void __attribute__((target_clones("default, arch=ivybridge"))) unused(void) {} // LINUX: ret ptr @unused.arch_ivybridge.0 // LINUX: ret ptr @unused.default.1 +// DARWIN: define {{.*}}void @unused.default.1() +// DARWIN: define {{.*}}void @unused.arch_ivybridge.0() +// DARWIN: define weak_odr ptr @unused.resolver() { +// DARWIN: ret ptr @unused.arch_ivybridge.0 +// DARWIN: ret ptr @unused.default.1 + // WINDOWS: define dso_local void @unused.default.1() // WINDOWS: define dso_local void @unused.arch_ivybridge.0() // WINDOWS: define weak_odr dso_local void @unused() comdat @@ -93,10 +122,13 @@ foo_inline2(void); int bar3(void) { // LINUX: define {{.*}}i32 @bar3() + // DARWIN: define {{.*}}i32 @bar3() // WINDOWS: define dso_local i32 @bar3() return foo_inline() + foo_inline2(); // LINUX: call i32 @foo_inline.ifunc() // LINUX: call i32 @foo_inline2.ifunc() + // DARWIN: call i32 @foo_inline.ifunc() + // DARWIN: call i32 @foo_inline2.ifunc() // WINDOWS: call i32 @foo_inline() // WINDOWS: call i32 @foo_inline2() } @@ -106,6 +138,11 @@ int bar3(void) { // LINUX: ret ptr @foo_inline.sse4.2.1 // LINUX: ret ptr @foo_inline.default.2 +// DARWIN: define weak_odr ptr @foo_inline.resolver() { +// DARWIN: ret ptr @foo_inline.arch_sandybridge.0 +// DARWIN: ret ptr @foo_inline.sse4.2.1 +// DARWIN: ret ptr @foo_inline.default.2 + // WINDOWS: define weak_odr dso_local i32 @foo_inline() comdat // WINDOWS: musttail call i32 @foo_inline.arch_sandybridge.0 // WINDOWS: musttail call i32 @foo_inline.sse4.2.1 @@ -118,6 +155,11 @@ foo_inline2(void){ return 0; } // LINUX: ret ptr @foo_inline2.sse4.2.1 // LINUX: ret ptr @foo_inline2.default.2 +// DARWIN: define weak_odr ptr @foo_inline2.resolver() { +// DARWIN: ret ptr @foo_inline2.arch_sandybridge.0 +// DARWIN: ret ptr @foo_inline2.sse4.2.1 +// DARWIN: ret ptr @foo_inline2.default.2 + // WINDOWS: define weak_odr dso_local i32 @foo_inline2() comdat // WINDOWS: musttail call i32 @foo_inline2.arch_sandybridge.0 // WINDOWS: musttail call i32 @foo_inline2.sse4.2.1 @@ -132,9 +174,11 @@ foo_used_no_defn(void); int test_foo_used_no_defn(void) { // LINUX: define {{.*}}i32 @test_foo_used_no_defn() + // DARWIN: define {{.*}}i32 @test_foo_used_no_defn() // WINDOWS: define dso_local i32 @test_foo_used_no_defn() return foo_used_no_defn(); // LINUX: call i32 @foo_used_no_defn.ifunc() + // DARWIN: call i32 @foo_used_no_defn.ifunc() // WINDOWS: call i32 @foo_used_no_defn() } @@ -143,6 +187,10 @@ int test_foo_used_no_defn(void) { // LINUX: ret ptr @foo_used_no_defn.sse4.2.0 // LINUX: ret ptr @foo_used_no_defn.default.1 +// DARWIN: define weak_odr ptr @foo_used_no_defn.resolver() { +// DARWIN: ret ptr @foo_used_no_defn.sse4.2.0 +// DARWIN: ret ptr @foo_used_no_defn.default.1 + // WINDOWS: define weak_odr dso_local i32 @foo_used_no_defn() comdat // WINDOWS: musttail call i32 @foo_used_no_defn.sse4.2.0 // WINDOWS: musttail call i32 @foo_used_no_defn.default.1 @@ -170,12 +218,37 @@ int isa_level(int) { return 0; } // LINUX: ret ptr @isa_level.arch_x86-64.0 // LINUX: ret ptr @isa_level.default.4 +// DARWIN: define{{.*}} i32 @isa_level.default.4( +// DARWIN: define{{.*}} i32 @isa_level.arch_x86-64.0( +// DARWIN: define{{.*}} i32 @isa_level.arch_x86-64-v2.1( +// DARWIN: define{{.*}} i32 @isa_level.arch_x86-64-v3.2( +// DARWIN: define{{.*}} i32 @isa_level.arch_x86-64-v4.3( +// DARWIN: define weak_odr ptr @isa_level.resolver() { +// DARWIN: call void @__cpu_indicator_init() +// DARWIN-NEXT: load i32, ptr getelementptr inbounds ([3 x i32], ptr @__cpu_features2, i32 0, i32 2) +// DARWIN-NEXT: and i32 %[[#]], 4 +// DARWIN: ret ptr @isa_level.arch_x86-64-v4.3 +// DARWIN: load i32, ptr getelementptr inbounds ([3 x i32], ptr @__cpu_features2, i32 0, i32 2) +// DARWIN-NEXT: and i32 %[[#]], 2 +// DARWIN: ret ptr @isa_level.arch_x86-64-v3.2 +// DARWIN: load i32, ptr getelementptr inbounds ([3 x i32], ptr @__cpu_features2, i32 0, i32 2) +// DARWIN-NEXT: and i32 %[[#]], 1 +// DARWIN: ret ptr @isa_level.arch_x86-64-v2.1 +// DARWIN: load i32, ptr getelementptr inbounds ([3 x i32], ptr @__cpu_features2, i32 0, i32 1) +// DARWIN-NEXT: and i32 %[[#]], -2147483648 +// DARWIN: ret ptr @isa_level.arch_x86-64.0 +// DARWIN: ret ptr @isa_level.default.4 + // Deferred emission of inline definitions. // LINUX: define linkonce i32 @foo_inline.arch_sandybridge.0() #[[SB:[0-9]+]] // LINUX: define linkonce i32 @foo_inline.default.2() #[[DEF:[0-9]+]] // LINUX: define linkonce i32 @foo_inline.sse4.2.1() #[[SSE42:[0-9]+]] +// DARWIN: define linkonce i32 @foo_inline.arch_sandybridge.0() #[[SB:[0-9]+]] +// DARWIN: define linkonce i32 @foo_inline.default.2() #[[DEF:[0-9]+]] +// DARWIN: define linkonce i32 @foo_inline.sse4.2.1() #[[SSE42:[0-9]+]] + // WINDOWS: define linkonce_odr dso_local i32 @foo_inline.arch_sandybridge.0() #[[SB:[0-9]+]] // WINDOWS: define linkonce_odr dso_local i32 @foo_inline.default.2() #[[DEF]] // WINDOWS: define linkonce_odr dso_local i32 @foo_inline.sse4.2.1() #[[SSE42:[0-9]+]] @@ -185,6 +258,10 @@ int isa_level(int) { return 0; } // LINUX: define linkonce i32 @foo_inline2.default.2() #[[DEF]] // LINUX: define linkonce i32 @foo_inline2.sse4.2.1() #[[SSE42]] +// DARWIN: define linkonce i32 @foo_inline2.arch_sandybridge.0() #[[SB]] +// DARWIN: define linkonce i32 @foo_inline2.default.2() #[[DEF]] +// DARWIN: define linkonce i32 @foo_inline2.sse4.2.1() #[[SSE42]] + // WINDOWS: define linkonce_odr dso_local i32 @foo_inline2.arch_sandybridge.0() #[[SB]] // WINDOWS: define linkonce_odr dso_local i32 @foo_inline2.default.2() #[[DEF]] // WINDOWS: define linkonce_odr dso_local i32 @foo_inline2.sse4.2.1() #[[SSE42]] @@ -193,6 +270,9 @@ int isa_level(int) { return 0; } // LINUX: declare i32 @foo_used_no_defn.default.1() // LINUX: declare i32 @foo_used_no_defn.sse4.2.0() +// DARWIN: declare i32 @foo_used_no_defn.default.1() +// DARWIN: declare i32 @foo_used_no_defn.sse4.2.0() + // WINDOWS: declare dso_local i32 @foo_used_no_defn.default.1() // WINDOWS: declare dso_local i32 @foo_used_no_defn.sse4.2.0() diff --git a/clang/test/CodeGen/attr-target-mv-func-ptrs.c b/clang/test/CodeGen/attr-target-mv-func-ptrs.c index b5f3a1b02f36f..7792ca53a4f65 100644 --- a/clang/test/CodeGen/attr-target-mv-func-ptrs.c +++ b/clang/test/CodeGen/attr-target-mv-func-ptrs.c @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix=LINUX +// RUN: %clang_cc1 -triple x86_64-apple-macosx -emit-llvm %s -o - | FileCheck %s --check-prefix=LINUX // RUN: %clang_cc1 -triple x86_64-windows-pc -emit-llvm %s -o - | FileCheck %s --check-prefix=WINDOWS int __attribute__((target("sse4.2"))) foo(int i) { return 0; } int __attribute__((target("arch=sandybridge"))) foo(int); diff --git a/clang/test/CodeGen/attr-target-mv.c b/clang/test/CodeGen/attr-target-mv.c index bdf8c49de4ae8..67d57b7f277e0 100644 --- a/clang/test/CodeGen/attr-target-mv.c +++ b/clang/test/CodeGen/attr-target-mv.c @@ -1,4 +1,5 @@ -// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix=LINUX +// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefixes=ITANIUM,LINUX +// RUN: %clang_cc1 -triple x86_64-apple-macosx -emit-llvm %s -o - | FileCheck %s --check-prefixes=ITANIUM,DARWIN // RUN: %clang_cc1 -triple x86_64-windows-pc -emit-llvm %s -o - | FileCheck %s --check-prefix=WINDOWS int __attribute__((target("sse4.2"))) foo(void) { return 0; } @@ -107,6 +108,8 @@ void calls_pr50025c(void) { pr50025c(); } // LINUX: $pr50025c.resolver = comdat any // LINUX: $pr50025b.resolver = comdat any +// DARWIN-NOT: comdat + // WINDOWS: $foo.resolver = comdat any // WINDOWS: $foo_inline.resolver = comdat any // WINDOWS: $foo_decls.resolver = comdat any @@ -133,73 +136,74 @@ void calls_pr50025c(void) { pr50025c(); } // LINUX: @llvm.compiler.used = appending global [2 x ptr] [ptr @foo_used, ptr @foo_used2.avx_sse4.2], section "llvm.metadata" +// DARWIN: @llvm.used = appending global [2 x ptr] [ptr @foo_used, ptr @foo_used2.avx_sse4.2], section "llvm.metadata" // WINDOWS: @llvm.used = appending global [2 x ptr] [ptr @foo_used, ptr @foo_used2.avx_sse4.2], section "llvm.metadata" -// LINUX: @foo.ifunc = weak_odr ifunc i32 (), ptr @foo.resolver -// LINUX: @foo_internal.ifunc = internal ifunc i32 (), ptr @foo_internal.resolver -// LINUX: @foo_inline.ifunc = weak_odr ifunc i32 (), ptr @foo_inline.resolver -// LINUX: @foo_decls.ifunc = weak_odr ifunc void (), ptr @foo_decls.resolver -// LINUX: @foo_multi.ifunc = weak_odr ifunc void (i32, double), ptr @foo_multi.resolver -// LINUX: @fwd_decl_default.ifunc = weak_odr ifunc i32 (), ptr @fwd_decl_default.resolver -// LINUX: @fwd_decl_avx.ifunc = weak_odr ifunc i32 (), ptr @fwd_decl_avx.resolver - -// LINUX: define{{.*}} i32 @foo.sse4.2() -// LINUX: ret i32 0 -// LINUX: define{{.*}} i32 @foo.arch_ivybridge() -// LINUX: ret i32 1 -// LINUX: define{{.*}} i32 @foo.arch_goldmont() -// LINUX: ret i32 3 -// LINUX: define{{.*}} i32 @foo.arch_goldmont-plus() -// LINUX: ret i32 4 -// LINUX: define{{.*}} i32 @foo.arch_tremont() -// LINUX: ret i32 5 -// LINUX: define{{.*}} i32 @foo.arch_icelake-client() -// LINUX: ret i32 6 -// LINUX: define{{.*}} i32 @foo.arch_icelake-server() -// LINUX: ret i32 7 -// LINUX: define{{.*}} i32 @foo.arch_cooperlake() -// LINUX: ret i32 8 -// LINUX: define{{.*}} i32 @foo.arch_tigerlake() -// LINUX: ret i32 9 -// LINUX: define{{.*}} i32 @foo.arch_sapphirerapids() -// LINUX: ret i32 10 -// LINUX: define{{.*}} i32 @foo.arch_alderlake() -// LINUX: ret i32 11 -// LINUX: define{{.*}} i32 @foo.arch_rocketlake() -// LINUX: ret i32 12 -// LINUX: define{{.*}} i32 @foo.arch_core2() -// LINUX: ret i32 13 -// LINUX: define{{.*}} i32 @foo.arch_raptorlake() -// LINUX: ret i32 14 -// LINUX: define{{.*}} i32 @foo.arch_meteorlake() -// LINUX: ret i32 15 -// LINUX: define{{.*}} i32 @foo.arch_sierraforest() -// LINUX: ret i32 16 -// LINUX: define{{.*}} i32 @foo.arch_grandridge() -// LINUX: ret i32 17 -// LINUX: define{{.*}} i32 @foo.arch_graniterapids() -// LINUX: ret i32 18 -// LINUX: define{{.*}} i32 @foo.arch_emeraldrapids() -// LINUX: ret i32 19 -// LINUX: define{{.*}} i32 @foo.arch_graniterapids-d() -// LINUX: ret i32 20 -// LINUX: define{{.*}} i32 @foo.arch_arrowlake() -// LINUX: ret i32 21 -// LINUX: define{{.*}} i32 @foo.arch_arrowlake-s() -// LINUX: ret i32 22 -// LINUX: define{{.*}} i32 @foo.arch_lunarlake() -// LINUX: ret i32 23 -// LINUX: define{{.*}} i32 @foo.arch_gracemont() -// LINUX: ret i32 24 -// LINUX: define{{.*}} i32 @foo.arch_pantherlake() -// LINUX: ret i32 25 -// LINUX: define{{.*}} i32 @foo.arch_clearwaterforest() -// LINUX: ret i32 26 -// LINUX: define{{.*}} i32 @foo() -// LINUX: ret i32 2 -// LINUX: define{{.*}} i32 @bar() -// LINUX: call i32 @foo.ifunc() +// ITANIUM: @foo.ifunc = weak_odr ifunc i32 (), ptr @foo.resolver +// ITANIUM: @foo_internal.ifunc = internal ifunc i32 (), ptr @foo_internal.resolver +// ITANIUM: @foo_inline.ifunc = weak_odr ifunc i32 (), ptr @foo_inline.resolver +// ITANIUM: @foo_decls.ifunc = weak_odr ifunc void (), ptr @foo_decls.resolver +// ITANIUM: @foo_multi.ifunc = weak_odr ifunc void (i32, double), ptr @foo_multi.resolver +// ITANIUM: @fwd_decl_default.ifunc = weak_odr ifunc i32 (), ptr @fwd_decl_default.resolver +// ITANIUM: @fwd_decl_avx.ifunc = weak_odr ifunc i32 (), ptr @fwd_decl_avx.resolver + +// ITANIUM: define{{.*}} i32 @foo.sse4.2() +// ITANIUM: ret i32 0 +// ITANIUM: define{{.*}} i32 @foo.arch_ivybridge() +// ITANIUM: ret i32 1 +// ITANIUM: define{{.*}} i32 @foo.arch_goldmont() +// ITANIUM: ret i32 3 +// ITANIUM: define{{.*}} i32 @foo.arch_goldmont-plus() +// ITANIUM: ret i32 4 +// ITANIUM: define{{.*}} i32 @foo.arch_tremont() +// ITANIUM: ret i32 5 +// ITANIUM: define{{.*}} i32 @foo.arch_icelake-client() +// ITANIUM: ret i32 6 +// ITANIUM: define{{.*}} i32 @foo.arch_icelake-server() +// ITANIUM: ret i32 7 +// ITANIUM: define{{.*}} i32 @foo.arch_cooperlake() +// ITANIUM: ret i32 8 +// ITANIUM: define{{.*}} i32 @foo.arch_tigerlake() +// ITANIUM: ret i32 9 +// ITANIUM: define{{.*}} i32 @foo.arch_sapphirerapids() +// ITANIUM: ret i32 10 +// ITANIUM: define{{.*}} i32 @foo.arch_alderlake() +// ITANIUM: ret i32 11 +// ITANIUM: define{{.*}} i32 @foo.arch_rocketlake() +// ITANIUM: ret i32 12 +// ITANIUM: define{{.*}} i32 @foo.arch_core2() +// ITANIUM: ret i32 13 +// ITANIUM: define{{.*}} i32 @foo.arch_raptorlake() +// ITANIUM: ret i32 14 +// ITANIUM: define{{.*}} i32 @foo.arch_meteorlake() +// ITANIUM: ret i32 15 +// ITANIUM: define{{.*}} i32 @foo.arch_sierraforest() +// ITANIUM: ret i32 16 +// ITANIUM: define{{.*}} i32 @foo.arch_grandridge() +// ITANIUM: ret i32 17 +// ITANIUM: define{{.*}} i32 @foo.arch_graniterapids() +// ITANIUM: ret i32 18 +// ITANIUM: define{{.*}} i32 @foo.arch_emeraldrapids() +// ITANIUM: ret i32 19 +// ITANIUM: define{{.*}} i32 @foo.arch_graniterapids-d() +// ITANIUM: ret i32 20 +// ITANIUM: define{{.*}} i32 @foo.arch_arrowlake() +// ITANIUM: ret i32 21 +// ITANIUM: define{{.*}} i32 @foo.arch_arrowlake-s() +// ITANIUM: ret i32 22 +// ITANIUM: define{{.*}} i32 @foo.arch_lunarlake() +// ITANIUM: ret i32 23 +// ITANIUM: define{{.*}} i32 @foo.arch_gracemont() +// ITANIUM: ret i32 24 +// ITANIUM: define{{.*}} i32 @foo.arch_pantherlake() +// ITANIUM: ret i32 25 +// ITANIUM: define{{.*}} i32 @foo.arch_clearwaterforest() +// ITANIUM: ret i32 26 +// ITANIUM: define{{.*}} i32 @foo() +// ITANIUM: ret i32 2 +// ITANIUM: define{{.*}} i32 @bar() +// ITANIUM: call i32 @foo.ifunc() // WINDOWS: define dso_local i32 @foo.sse4.2() // WINDOWS: ret i32 0 @@ -258,12 +262,13 @@ void calls_pr50025c(void) { pr50025c(); } // WINDOWS: define dso_local i32 @bar() // WINDOWS: call i32 @foo.resolver() -// LINUX: define weak_odr ptr @foo.resolver() comdat -// LINUX: call void @__cpu_indicator_init() -// LINUX: ret ptr @foo.arch_sandybridge -// LINUX: ret ptr @foo.arch_ivybridge -// LINUX: ret ptr @foo.sse4.2 -// LINUX: ret ptr @foo +// ITANIUM: define weak_odr ptr @foo.resolver() +// LINUX-SAME: comdat +// ITANIUM: call void @__cpu_indicator_init() +// ITANIUM: ret ptr @foo.arch_sandybridge +// ITANIUM: ret ptr @foo.arch_ivybridge +// ITANIUM: ret ptr @foo.sse4.2 +// ITANIUM: ret ptr @foo // WINDOWS: define weak_odr dso_local i32 @foo.resolver() comdat // WINDOWS: call void @__cpu_indicator_init() @@ -273,22 +278,23 @@ void calls_pr50025c(void) { pr50025c(); } // WINDOWS: call i32 @foo /// Internal linkage resolvers do not use comdat. -// LINUX: define internal ptr @foo_internal.resolver() { +// ITANIUM: define internal ptr @foo_internal.resolver() { // WINDOWS: define internal i32 @foo_internal.resolver() { -// LINUX: define{{.*}} i32 @bar2() -// LINUX: call i32 @foo_inline.ifunc() +// ITANIUM: define{{.*}} i32 @bar2() +// ITANIUM: call i32 @foo_inline.ifunc() // WINDOWS: define dso_local i32 @bar2() // WINDOWS: call i32 @foo_inline.resolver() -// LINUX: define weak_odr ptr @foo_inline.resolver() comdat -// LINUX: call void @__cpu_indicator_init() -// LINUX: ret ptr @foo_inline.arch_sandybridge -// LINUX: ret ptr @foo_inline.arch_ivybridge -// LINUX: ret ptr @foo_inline.sse4.2 -// LINUX: ret ptr @foo_inline +// ITANIUM: define weak_odr ptr @foo_inline.resolver() +// LINUX-SAME: comdat +// ITANIUM: call void @__cpu_indicator_init() +// ITANIUM: ret ptr @foo_inline.arch_sandybridge +// ITANIUM: ret ptr @foo_inline.arch_ivybridge +// ITANIUM: ret ptr @foo_inline.sse4.2 +// ITANIUM: ret ptr @foo_inline // WINDOWS: define weak_odr dso_local i32 @foo_inline.resolver() comdat // WINDOWS: call void @__cpu_indicator_init() @@ -297,38 +303,40 @@ void calls_pr50025c(void) { pr50025c(); } // WINDOWS: call i32 @foo_inline.sse4.2 // WINDOWS: call i32 @foo_inline -// LINUX: define{{.*}} void @bar3() -// LINUX: call void @foo_decls.ifunc() +// ITANIUM: define{{.*}} void @bar3() +// ITANIUM: call void @foo_decls.ifunc() // WINDOWS: define dso_local void @bar3() // WINDOWS: call void @foo_decls.resolver() -// LINUX: define weak_odr ptr @foo_decls.resolver() comdat -// LINUX: ret ptr @foo_decls.sse4.2 -// LINUX: ret ptr @foo_decls +// ITANIUM: define weak_odr ptr @foo_decls.resolver() +// LINUX-SAME: comdat +// ITANIUM: ret ptr @foo_decls.sse4.2 +// ITANIUM: ret ptr @foo_decls // WINDOWS: define weak_odr dso_local void @foo_decls.resolver() comdat // WINDOWS: call void @foo_decls.sse4.2 // WINDOWS: call void @foo_decls -// LINUX: define{{.*}} void @bar4() -// LINUX: call void @foo_multi.ifunc(i32 noundef 1, double noundef 5.{{[0+e]*}}) +// ITANIUM: define{{.*}} void @bar4() +// ITANIUM: call void @foo_multi.ifunc(i32 noundef 1, double noundef 5.{{[0+e]*}}) // WINDOWS: define dso_local void @bar4() // WINDOWS: call void @foo_multi.resolver(i32 noundef 1, double noundef 5.{{[0+e]*}}) -// LINUX: define weak_odr ptr @foo_multi.resolver() comdat -// LINUX: and i32 %{{.*}}, 4352 -// LINUX: icmp eq i32 %{{.*}}, 4352 -// LINUX: ret ptr @foo_multi.fma4_sse4.2 -// LINUX: icmp eq i32 %{{.*}}, 12 -// LINUX: and i32 %{{.*}}, 4352 -// LINUX: icmp eq i32 %{{.*}}, 4352 -// LINUX: ret ptr @foo_multi.arch_ivybridge_fma4_sse4.2 -// LINUX: and i32 %{{.*}}, 768 -// LINUX: icmp eq i32 %{{.*}}, 768 -// LINUX: ret ptr @foo_multi.avx_sse4.2 -// LINUX: ret ptr @foo_multi +// ITANIUM: define weak_odr ptr @foo_multi.resolver() +// LINUX-SAME: comdat +// ITANIUM: and i32 %{{.*}}, 4352 +// ITANIUM: icmp eq i32 %{{.*}}, 4352 +// ITANIUM: ret ptr @foo_multi.fma4_sse4.2 +// ITANIUM: icmp eq i32 %{{.*}}, 12 +// ITANIUM: and i32 %{{.*}}, 4352 +// ITANIUM: icmp eq i32 %{{.*}}, 4352 +// ITANIUM: ret ptr @foo_multi.arch_ivybridge_fma4_sse4.2 +// ITANIUM: and i32 %{{.*}}, 768 +// ITANIUM: icmp eq i32 %{{.*}}, 768 +// ITANIUM: ret ptr @foo_multi.avx_sse4.2 +// ITANIUM: ret ptr @foo_multi // WINDOWS: define weak_odr dso_local void @foo_multi.resolver(i32 %0, double %1) comdat // WINDOWS: and i32 %{{.*}}, 4352 @@ -347,12 +355,12 @@ void calls_pr50025c(void) { pr50025c(); } // WINDOWS: call void @foo_multi(i32 %0, double %1) // WINDOWS-NEXT: ret void -// LINUX: define{{.*}} i32 @fwd_decl_default() -// LINUX: ret i32 2 -// LINUX: define{{.*}} i32 @fwd_decl_avx.avx() -// LINUX: ret i32 2 -// LINUX: define{{.*}} i32 @fwd_decl_avx() -// LINUX: ret i32 2 +// ITANIUM: define{{.*}} i32 @fwd_decl_default() +// ITANIUM: ret i32 2 +// ITANIUM: define{{.*}} i32 @fwd_decl_avx.avx() +// ITANIUM: ret i32 2 +// ITANIUM: define{{.*}} i32 @fwd_decl_avx() +// ITANIUM: ret i32 2 // WINDOWS: define dso_local i32 @fwd_decl_default() // WINDOWS: ret i32 2 @@ -361,21 +369,23 @@ void calls_pr50025c(void) { pr50025c(); } // WINDOWS: define dso_local i32 @fwd_decl_avx() // WINDOWS: ret i32 2 -// LINUX: define{{.*}} void @bar5() -// LINUX: call i32 @fwd_decl_default.ifunc() -// LINUX: call i32 @fwd_decl_avx.ifunc() +// ITANIUM: define{{.*}} void @bar5() +// ITANIUM: call i32 @fwd_decl_default.ifunc() +// ITANIUM: call i32 @fwd_decl_avx.ifunc() // WINDOWS: define dso_local void @bar5() // WINDOWS: call i32 @fwd_decl_default.resolver() // WINDOWS: call i32 @fwd_decl_avx.resolver() -// LINUX: define weak_odr ptr @fwd_decl_default.resolver() comdat -// LINUX: call void @__cpu_indicator_init() -// LINUX: ret ptr @fwd_decl_default -// LINUX: define weak_odr ptr @fwd_decl_avx.resolver() comdat -// LINUX: call void @__cpu_indicator_init() -// LINUX: ret ptr @fwd_decl_avx.avx -// LINUX: ret ptr @fwd_decl_avx +// ITANIUM: define weak_odr ptr @fwd_decl_default.resolver() +// LINUX-SAME: comdat +// ITANIUM: call void @__cpu_indicator_init() +// ITANIUM: ret ptr @fwd_decl_default +// ITANIUM: define weak_odr ptr @fwd_decl_avx.resolver() +// LINUX-SAME: comdat +// ITANIUM: call void @__cpu_indicator_init() +// ITANIUM: ret ptr @fwd_decl_avx.avx +// ITANIUM: ret ptr @fwd_decl_avx // WINDOWS: define weak_odr dso_local i32 @fwd_decl_default.resolver() comdat // WINDOWS: call void @__cpu_indicator_init() @@ -385,55 +395,55 @@ void calls_pr50025c(void) { pr50025c(); } // WINDOWS: call i32 @fwd_decl_avx.avx // WINDOWS: call i32 @fwd_decl_avx -// LINUX: define{{.*}} i32 @changed_to_mv.avx() -// LINUX: define{{.*}} i32 @changed_to_mv.fma4() +// ITANIUM: define{{.*}} i32 @changed_to_mv.avx() +// ITANIUM: define{{.*}} i32 @changed_to_mv.fma4() // WINDOWS: define dso_local i32 @changed_to_mv.avx() // WINDOWS: define dso_local i32 @changed_to_mv.fma4() -// LINUX: define linkonce void @foo_used(i32 noundef %{{.*}}, double noundef %{{.*}}) -// LINUX-NOT: @foo_used.avx_sse4.2( -// LINUX-NOT: @foo_used2( -// LINUX: define linkonce void @foo_used2.avx_sse4.2(i32 noundef %{{.*}}, double noundef %{{.*}}) +// ITANIUM: define linkonce void @foo_used(i32 noundef %{{.*}}, double noundef %{{.*}}) +// ITANIUM-NOT: @foo_used.avx_sse4.2( +// ITANIUM-NOT: @foo_used2( +// ITANIUM: define linkonce void @foo_used2.avx_sse4.2(i32 noundef %{{.*}}, double noundef %{{.*}}) // WINDOWS: define linkonce_odr dso_local void @foo_used(i32 noundef %{{.*}}, double noundef %{{.*}}) // WINDOWS-NOT: @foo_used.avx_sse4.2( // WINDOWS-NOT: @foo_used2( // WINDOWS: define linkonce_odr dso_local void @foo_used2.avx_sse4.2(i32 noundef %{{.*}}, double noundef %{{.*}}) -// LINUX: declare i32 @foo.arch_sandybridge() +// ITANIUM: declare i32 @foo.arch_sandybridge() // WINDOWS: declare dso_local i32 @foo.arch_sandybridge() -// LINUX: define linkonce i32 @foo_inline.sse4.2() -// LINUX: ret i32 0 +// ITANIUM: define linkonce i32 @foo_inline.sse4.2() +// ITANIUM: ret i32 0 // WINDOWS: define linkonce_odr dso_local i32 @foo_inline.sse4.2() // WINDOWS: ret i32 0 -// LINUX: declare i32 @foo_inline.arch_sandybridge() +// ITANIUM: declare i32 @foo_inline.arch_sandybridge() // WINDOWS: declare dso_local i32 @foo_inline.arch_sandybridge() -// LINUX: define linkonce i32 @foo_inline.arch_ivybridge() -// LINUX: ret i32 1 -// LINUX: define linkonce i32 @foo_inline() -// LINUX: ret i32 2 +// ITANIUM: define linkonce i32 @foo_inline.arch_ivybridge() +// ITANIUM: ret i32 1 +// ITANIUM: define linkonce i32 @foo_inline() +// ITANIUM: ret i32 2 // WINDOWS: define linkonce_odr dso_local i32 @foo_inline.arch_ivybridge() // WINDOWS: ret i32 1 // WINDOWS: define linkonce_odr dso_local i32 @foo_inline() // WINDOWS: ret i32 2 -// LINUX: define linkonce void @foo_decls() -// LINUX: define linkonce void @foo_decls.sse4.2() +// ITANIUM: define linkonce void @foo_decls() +// ITANIUM: define linkonce void @foo_decls.sse4.2() // WINDOWS: define linkonce_odr dso_local void @foo_decls() // WINDOWS: define linkonce_odr dso_local void @foo_decls.sse4.2() -// LINUX: define linkonce void @foo_multi(i32 noundef %{{[^,]+}}, double noundef %{{[^\)]+}}) -// LINUX: define linkonce void @foo_multi.avx_sse4.2(i32 noundef %{{[^,]+}}, double noundef %{{[^\)]+}}) -// LINUX: define linkonce void @foo_multi.fma4_sse4.2(i32 noundef %{{[^,]+}}, double noundef %{{[^\)]+}}) -// LINUX: define linkonce void @foo_multi.arch_ivybridge_fma4_sse4.2(i32 noundef %{{[^,]+}}, double noundef %{{[^\)]+}}) +// ITANIUM: define linkonce void @foo_multi(i32 noundef %{{[^,]+}}, double noundef %{{[^\)]+}}) +// ITANIUM: define linkonce void @foo_multi.avx_sse4.2(i32 noundef %{{[^,]+}}, double noundef %{{[^\)]+}}) +// ITANIUM: define linkonce void @foo_multi.fma4_sse4.2(i32 noundef %{{[^,]+}}, double noundef %{{[^\)]+}}) +// ITANIUM: define linkonce void @foo_multi.arch_ivybridge_fma4_sse4.2(i32 noundef %{{[^,]+}}, double noundef %{{[^\)]+}}) // WINDOWS: define linkonce_odr dso_local void @foo_multi(i32 noundef %{{[^,]+}}, double noundef %{{[^\)]+}}) // WINDOWS: define linkonce_odr dso_local void @foo_multi.avx_sse4.2(i32 noundef %{{[^,]+}}, double noundef %{{[^\)]+}}) @@ -441,22 +451,23 @@ void calls_pr50025c(void) { pr50025c(); } // WINDOWS: define linkonce_odr dso_local void @foo_multi.arch_ivybridge_fma4_sse4.2(i32 noundef %{{[^,]+}}, double noundef %{{[^\)]+}}) // Ensure that we emit the 'static' function here. -// LINUX: define linkonce void @pr50025() -// LINUX: call void @must_be_emitted -// LINUX: define internal void @must_be_emitted() +// ITANIUM: define linkonce void @pr50025() +// ITANIUM: call void @must_be_emitted +// ITANIUM: define internal void @must_be_emitted() // WINDOWS: define linkonce_odr dso_local void @pr50025() #{{[0-9]*}} comdat // WINDOWS: call void @must_be_emitted // WINDOWS: define internal void @must_be_emitted() -// LINUX: define linkonce void @pr50025c() -// LINUX: call void @pr50025b.ifunc() +// ITANIUM: define linkonce void @pr50025c() +// ITANIUM: call void @pr50025b.ifunc() // WINDOWS: define linkonce_odr dso_local void @pr50025c() #{{[0-9]*}} comdat // WINDOWS: call void @pr50025b.resolver() -// LINUX: define weak_odr ptr @pr50025b.resolver() comdat -// LINUX: ret ptr @pr50025b -// LINUX: define linkonce void @pr50025b() -// LINUX: call void @must_be_emitted() +// ITANIUM: define weak_odr ptr @pr50025b.resolver() +// LINUX-SAME: comdat +// ITANIUM: ret ptr @pr50025b +// ITANIUM: define linkonce void @pr50025b() +// ITANIUM: call void @must_be_emitted() // WINDOWS: define weak_odr dso_local void @pr50025b.resolver() comdat // WINDOWS: musttail call void @pr50025b() // WINDOWS: define linkonce_odr dso_local void @pr50025b() #{{[0-9]*}} comdat diff --git a/clang/test/CodeGenCXX/attr-cpuspecific.cpp b/clang/test/CodeGenCXX/attr-cpuspecific.cpp index 60cba6da01754..2294ee4b4c153 100644 --- a/clang/test/CodeGenCXX/attr-cpuspecific.cpp +++ b/clang/test/CodeGenCXX/attr-cpuspecific.cpp @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck %s --check-prefix=LINUX +// RUN: %clang_cc1 -triple x86_64-apple-macosx -emit-llvm -o - %s | FileCheck %s --check-prefix=LINUX // RUN: %clang_cc1 -triple x86_64-windows-pc -fms-compatibility -emit-llvm -o - %s | FileCheck %s --check-prefix=WINDOWS struct S { diff --git a/clang/test/CodeGenCXX/attr-target-clones.cpp b/clang/test/CodeGenCXX/attr-target-clones.cpp index 86293b98dbbd3..d540c8f8ac289 100644 --- a/clang/test/CodeGenCXX/attr-target-clones.cpp +++ b/clang/test/CodeGenCXX/attr-target-clones.cpp @@ -1,20 +1,24 @@ -// RUN: %clang_cc1 -std=c++11 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix=LINUX +// RUN: %clang_cc1 -std=c++11 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefixes=ITANIUM,LINUX +// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-macosx -emit-llvm %s -o - | FileCheck %s --check-prefixes=ITANIUM,DARWIN // RUN: %clang_cc1 -std=c++11 -triple x86_64-windows-pc -emit-llvm %s -o - | FileCheck %s --check-prefix=WINDOWS +// DARWIN-NOT: comdat + // Overloaded ifuncs -// LINUX: @_Z10overloadedi.ifunc = weak_odr ifunc i32 (i32), ptr @_Z10overloadedi.resolver -// LINUX: @_Z10overloadedPKc.ifunc = weak_odr ifunc i32 (ptr), ptr @_Z10overloadedPKc.resolver +// ITANIUM: @_Z10overloadedi.ifunc = weak_odr ifunc i32 (i32), ptr @_Z10overloadedi.resolver +// ITANIUM: @_Z10overloadedPKc.ifunc = weak_odr ifunc i32 (ptr), ptr @_Z10overloadedPKc.resolver // struct 'C' ifuncs, note the 'float, U' one doesn't get one. -// LINUX: @_ZN1CIssE3fooEv.ifunc = weak_odr ifunc i32 (ptr), ptr @_ZN1CIssE3fooEv.resolver -// LINUX: @_ZN1CIisE3fooEv.ifunc = weak_odr ifunc i32 (ptr), ptr @_ZN1CIisE3fooEv.resolver -// LINUX: @_ZN1CIdfE3fooEv.ifunc = weak_odr ifunc i32 (ptr), ptr @_ZN1CIdfE3fooEv.resolver +// ITANIUM: @_ZN1CIssE3fooEv.ifunc = weak_odr ifunc i32 (ptr), ptr @_ZN1CIssE3fooEv.resolver +// ITANIUM: @_ZN1CIisE3fooEv.ifunc = weak_odr ifunc i32 (ptr), ptr @_ZN1CIisE3fooEv.resolver +// ITANIUM: @_ZN1CIdfE3fooEv.ifunc = weak_odr ifunc i32 (ptr), ptr @_ZN1CIdfE3fooEv.resolver int __attribute__((target_clones("sse4.2", "default"))) overloaded(int) { return 1; } -// LINUX: define {{.*}}i32 @_Z10overloadedi.sse4.2.0(i32{{.+}}) -// LINUX: define {{.*}}i32 @_Z10overloadedi.default.1(i32{{.+}}) -// LINUX: define weak_odr ptr @_Z10overloadedi.resolver() comdat -// LINUX: ret ptr @_Z10overloadedi.sse4.2.0 -// LINUX: ret ptr @_Z10overloadedi.default.1 +// ITANIUM: define {{.*}}i32 @_Z10overloadedi.sse4.2.0(i32{{.+}}) +// ITANIUM: define {{.*}}i32 @_Z10overloadedi.default.1(i32{{.+}}) +// ITANIUM: define weak_odr ptr @_Z10overloadedi.resolver() +// LINUX-SAME: comdat +// ITANIUM: ret ptr @_Z10overloadedi.sse4.2.0 +// ITANIUM: ret ptr @_Z10overloadedi.default.1 // WINDOWS: define dso_local noundef i32 @"?overloaded@@YAHH@Z.sse4.2.0"(i32{{.+}}) // WINDOWS: define dso_local noundef i32 @"?overloaded@@YAHH@Z.default.1"(i32{{.+}}) @@ -23,11 +27,12 @@ int __attribute__((target_clones("sse4.2", "default"))) overloaded(int) { return // WINDOWS: call i32 @"?overloaded@@YAHH@Z.default.1" int __attribute__((target_clones("arch=ivybridge", "default"))) overloaded(const char *) { return 2; } -// LINUX: define {{.*}}i32 @_Z10overloadedPKc.arch_ivybridge.0(ptr{{.+}}) -// LINUX: define {{.*}}i32 @_Z10overloadedPKc.default.1(ptr{{.+}}) -// LINUX: define weak_odr ptr @_Z10overloadedPKc.resolver() comdat -// LINUX: ret ptr @_Z10overloadedPKc.arch_ivybridge.0 -// LINUX: ret ptr @_Z10overloadedPKc.default.1 +// ITANIUM: define {{.*}}i32 @_Z10overloadedPKc.arch_ivybridge.0(ptr{{.+}}) +// ITANIUM: define {{.*}}i32 @_Z10overloadedPKc.default.1(ptr{{.+}}) +// ITANIUM: define weak_odr ptr @_Z10overloadedPKc.resolver() +// LINUX-SAME: comdat +// ITANIUM: ret ptr @_Z10overloadedPKc.arch_ivybridge.0 +// ITANIUM: ret ptr @_Z10overloadedPKc.default.1 // WINDOWS: define dso_local noundef i32 @"?overloaded@@YAHPEBD@Z.arch_ivybridge.0"(ptr{{.+}}) // WINDOWS: define dso_local noundef i32 @"?overloaded@@YAHPEBD@Z.default.1"(ptr{{.+}}) @@ -37,10 +42,10 @@ int __attribute__((target_clones("arch=ivybridge", "default"))) overloaded(const void use_overloaded() { overloaded(1); - // LINUX: call noundef i32 @_Z10overloadedi.ifunc + // ITANIUM: call noundef i32 @_Z10overloadedi.ifunc // WINDOWS: call noundef i32 @"?overloaded@@YAHH@Z" overloaded(nullptr); - // LINUX: call noundef i32 @_Z10overloadedPKc.ifunc + // ITANIUM: call noundef i32 @_Z10overloadedPKc.ifunc // WINDOWS: call noundef i32 @"?overloaded@@YAHPEBD@Z" } @@ -64,53 +69,56 @@ int __attribute__((target_clones("sse4.2", "default"))) foo(){ return 3;} void uses_specialized() { C c; c.foo(); - // LINUX: call noundef i32 @_ZN1CIssE3fooEv.ifunc(ptr + // ITANIUM: call noundef i32 @_ZN1CIssE3fooEv.ifunc(ptr // WINDOWS: call noundef i32 @"?foo@?$C@FF@@QEAAHXZ"(ptr C c2; c2.foo(); - // LINUX: call noundef i32 @_ZN1CIisE3fooEv.ifunc(ptr + // ITANIUM: call noundef i32 @_ZN1CIisE3fooEv.ifunc(ptr // WINDOWS: call noundef i32 @"?foo@?$C@HF@@QEAAHXZ"(ptr C c3; c3.foo(); // Note this is not an ifunc/mv - // LINUX: call noundef i32 @_ZN1CIfsE3fooEv(ptr + // ITANIUM: call noundef i32 @_ZN1CIfsE3fooEv(ptr // WINDOWS: call noundef i32 @"?foo@?$C@MF@@QEAAHXZ"(ptr C c4; c4.foo(); - // LINUX: call noundef i32 @_ZN1CIdfE3fooEv.ifunc(ptr + // ITANIUM: call noundef i32 @_ZN1CIdfE3fooEv.ifunc(ptr // WINDOWS: call noundef i32 @"?foo@?$C@NM@@QEAAHXZ"(ptr } -// LINUX: define weak_odr ptr @_ZN1CIssE3fooEv.resolver() comdat -// LINUX: ret ptr @_ZN1CIssE3fooEv.sse4.2.0 -// LINUX: ret ptr @_ZN1CIssE3fooEv.default.1 +// ITANIUM: define weak_odr ptr @_ZN1CIssE3fooEv.resolver() +// LINUX-SAME: comdat +// ITANIUM: ret ptr @_ZN1CIssE3fooEv.sse4.2.0 +// ITANIUM: ret ptr @_ZN1CIssE3fooEv.default.1 // WINDOWS: define {{.*}}i32 @"?foo@?$C@FF@@QEAAHXZ"(ptr // WINDOWS: call i32 @"?foo@?$C@FF@@QEAAHXZ.sse4.2.0" // WINDOWS: call i32 @"?foo@?$C@FF@@QEAAHXZ.default.1" -// LINUX: define weak_odr ptr @_ZN1CIisE3fooEv.resolver() comdat -// LINUX: ret ptr @_ZN1CIisE3fooEv.sse4.2.0 -// LINUX: ret ptr @_ZN1CIisE3fooEv.default.1 +// ITANIUM: define weak_odr ptr @_ZN1CIisE3fooEv.resolver() +// LINUX-SAME: comdat +// ITANIUM: ret ptr @_ZN1CIisE3fooEv.sse4.2.0 +// ITANIUM: ret ptr @_ZN1CIisE3fooEv.default.1 // WINDOWS: define {{.*}}i32 @"?foo@?$C@HF@@QEAAHXZ"(ptr // WINDOWS: call i32 @"?foo@?$C@HF@@QEAAHXZ.sse4.2.0" // WINDOWS: call i32 @"?foo@?$C@HF@@QEAAHXZ.default.1" -// LINUX: define weak_odr ptr @_ZN1CIdfE3fooEv.resolver() comdat -// LINUX: ret ptr @_ZN1CIdfE3fooEv.sse4.2.0 -// LINUX: ret ptr @_ZN1CIdfE3fooEv.default.1 +// ITANIUM: define weak_odr ptr @_ZN1CIdfE3fooEv.resolver() +// LINUX-SAME: comdat +// ITANIUM: ret ptr @_ZN1CIdfE3fooEv.sse4.2.0 +// ITANIUM: ret ptr @_ZN1CIdfE3fooEv.default.1 // WINDOWS: define {{.*}}i32 @"?foo@?$C@NM@@QEAAHXZ"(ptr // WINDOWS: call i32 @"?foo@?$C@NM@@QEAAHXZ.sse4.2.0" // WINDOWS: call i32 @"?foo@?$C@NM@@QEAAHXZ.default.1" -// LINUX: define {{.*}}i32 @_ZN1CIssE3fooEv.sse4.2.0(ptr -// LINUX: define {{.*}}i32 @_ZN1CIssE3fooEv.default.1(ptr -// LINUX: define {{.*}}i32 @_ZN1CIisE3fooEv.sse4.2.0(ptr -// LINUX: define {{.*}}i32 @_ZN1CIisE3fooEv.default.1(ptr -// LINUX: define {{.*}}i32 @_ZN1CIdfE3fooEv.sse4.2.0(ptr -// LINUX: define {{.*}}i32 @_ZN1CIdfE3fooEv.default.1(ptr +// ITANIUM: define {{.*}}i32 @_ZN1CIssE3fooEv.sse4.2.0(ptr +// ITANIUM: define {{.*}}i32 @_ZN1CIssE3fooEv.default.1(ptr +// ITANIUM: define {{.*}}i32 @_ZN1CIisE3fooEv.sse4.2.0(ptr +// ITANIUM: define {{.*}}i32 @_ZN1CIisE3fooEv.default.1(ptr +// ITANIUM: define {{.*}}i32 @_ZN1CIdfE3fooEv.sse4.2.0(ptr +// ITANIUM: define {{.*}}i32 @_ZN1CIdfE3fooEv.default.1(ptr // WINDOWS: define {{.*}}i32 @"?foo@?$C@FF@@QEAAHXZ.sse4.2.0"(ptr // WINDOWS: define {{.*}}i32 @"?foo@?$C@FF@@QEAAHXZ.default.1"(ptr diff --git a/clang/test/CodeGenCXX/attr-target-mv-diff-ns.cpp b/clang/test/CodeGenCXX/attr-target-mv-diff-ns.cpp index 1157450835bda..a6ec608240c76 100644 --- a/clang/test/CodeGenCXX/attr-target-mv-diff-ns.cpp +++ b/clang/test/CodeGenCXX/attr-target-mv-diff-ns.cpp @@ -1,4 +1,5 @@ -// RUN: %clang_cc1 -std=c++11 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix=LINUX +// RUN: %clang_cc1 -std=c++11 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefixes=ITANIUM,LINUX +// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-macosx -emit-llvm %s -o - | FileCheck %s --check-prefixes=ITANIUM,DARWIN // RUN: %clang_cc1 -std=c++11 -triple x86_64-windows-pc -emit-llvm %s -o - | FileCheck %s --check-prefix=WINDOWS // Test ensures that this properly differentiates between types in different // namespaces. @@ -18,15 +19,17 @@ int bar() { return foo(1) + ns::foo(2); } -// LINUX: @_Z3fooi.ifunc = weak_odr ifunc i32 (i32), ptr @_Z3fooi.resolver -// LINUX: @_ZN2ns3fooEi.ifunc = weak_odr ifunc i32 (i32), ptr @_ZN2ns3fooEi.resolver +// DARWIN-NOT: comdat -// LINUX: define{{.*}} i32 @_Z3fooi.sse4.2(i32 noundef %0) -// LINUX: ret i32 0 -// LINUX: define{{.*}} i32 @_Z3fooi.arch_ivybridge(i32 noundef %0) -// LINUX: ret i32 1 -// LINUX: define{{.*}} i32 @_Z3fooi(i32 noundef %0) -// LINUX: ret i32 2 +// ITANIUM: @_Z3fooi.ifunc = weak_odr ifunc i32 (i32), ptr @_Z3fooi.resolver +// ITANIUM: @_ZN2ns3fooEi.ifunc = weak_odr ifunc i32 (i32), ptr @_ZN2ns3fooEi.resolver + +// ITANIUM: define{{.*}} i32 @_Z3fooi.sse4.2(i32 noundef %0) +// ITANIUM: ret i32 0 +// ITANIUM: define{{.*}} i32 @_Z3fooi.arch_ivybridge(i32 noundef %0) +// ITANIUM: ret i32 1 +// ITANIUM: define{{.*}} i32 @_Z3fooi(i32 noundef %0) +// ITANIUM: ret i32 2 // WINDOWS: define dso_local noundef i32 @"?foo@@YAHH@Z.sse4.2"(i32 noundef %0) // WINDOWS: ret i32 0 @@ -35,12 +38,12 @@ int bar() { // WINDOWS: define dso_local noundef i32 @"?foo@@YAHH@Z"(i32 noundef %0) // WINDOWS: ret i32 2 -// LINUX: define{{.*}} i32 @_ZN2ns3fooEi.sse4.2(i32 noundef %0) -// LINUX: ret i32 0 -// LINUX: define{{.*}} i32 @_ZN2ns3fooEi.arch_ivybridge(i32 noundef %0) -// LINUX: ret i32 1 -// LINUX: define{{.*}} i32 @_ZN2ns3fooEi(i32 noundef %0) -// LINUX: ret i32 2 +// ITANIUM: define{{.*}} i32 @_ZN2ns3fooEi.sse4.2(i32 noundef %0) +// ITANIUM: ret i32 0 +// ITANIUM: define{{.*}} i32 @_ZN2ns3fooEi.arch_ivybridge(i32 noundef %0) +// ITANIUM: ret i32 1 +// ITANIUM: define{{.*}} i32 @_ZN2ns3fooEi(i32 noundef %0) +// ITANIUM: ret i32 2 // WINDOWS: define dso_local noundef i32 @"?foo@ns@@YAHH@Z.sse4.2"(i32 noundef %0) // WINDOWS: ret i32 0 @@ -49,19 +52,20 @@ int bar() { // WINDOWS: define dso_local noundef i32 @"?foo@ns@@YAHH@Z"(i32 noundef %0) // WINDOWS: ret i32 2 -// LINUX: define{{.*}} i32 @_Z3barv() -// LINUX: call noundef i32 @_Z3fooi.ifunc(i32 noundef 1) -// LINUX: call noundef i32 @_ZN2ns3fooEi.ifunc(i32 noundef 2) +// ITANIUM: define{{.*}} i32 @_Z3barv() +// ITANIUM: call noundef i32 @_Z3fooi.ifunc(i32 noundef 1) +// ITANIUM: call noundef i32 @_ZN2ns3fooEi.ifunc(i32 noundef 2) // WINDOWS: define dso_local noundef i32 @"?bar@@YAHXZ"() // WINDOWS: call noundef i32 @"?foo@@YAHH@Z.resolver"(i32 noundef 1) // WINDOWS: call noundef i32 @"?foo@ns@@YAHH@Z.resolver"(i32 noundef 2) -// LINUX: define weak_odr ptr @_Z3fooi.resolver() comdat -// LINUX: ret ptr @_Z3fooi.arch_sandybridge -// LINUX: ret ptr @_Z3fooi.arch_ivybridge -// LINUX: ret ptr @_Z3fooi.sse4.2 -// LINUX: ret ptr @_Z3fooi +// ITANIUM: define weak_odr ptr @_Z3fooi.resolver() +// LINUX-SAME: comdat +// ITANIUM: ret ptr @_Z3fooi.arch_sandybridge +// ITANIUM: ret ptr @_Z3fooi.arch_ivybridge +// ITANIUM: ret ptr @_Z3fooi.sse4.2 +// ITANIUM: ret ptr @_Z3fooi // WINDOWS: define weak_odr dso_local i32 @"?foo@@YAHH@Z.resolver"(i32 %0) comdat // WINDOWS: call i32 @"?foo@@YAHH@Z.arch_sandybridge"(i32 %0) @@ -69,11 +73,12 @@ int bar() { // WINDOWS: call i32 @"?foo@@YAHH@Z.sse4.2"(i32 %0) // WINDOWS: call i32 @"?foo@@YAHH@Z"(i32 %0) -// LINUX: define weak_odr ptr @_ZN2ns3fooEi.resolver() comdat -// LINUX: ret ptr @_ZN2ns3fooEi.arch_sandybridge -// LINUX: ret ptr @_ZN2ns3fooEi.arch_ivybridge -// LINUX: ret ptr @_ZN2ns3fooEi.sse4.2 -// LINUX: ret ptr @_ZN2ns3fooEi +// ITANIUM: define weak_odr ptr @_ZN2ns3fooEi.resolver() +// LINUX-SAME: comdat +// ITANIUM: ret ptr @_ZN2ns3fooEi.arch_sandybridge +// ITANIUM: ret ptr @_ZN2ns3fooEi.arch_ivybridge +// ITANIUM: ret ptr @_ZN2ns3fooEi.sse4.2 +// ITANIUM: ret ptr @_ZN2ns3fooEi // WINDOWS: define weak_odr dso_local i32 @"?foo@ns@@YAHH@Z.resolver"(i32 %0) comdat // WINDOWS: call i32 @"?foo@ns@@YAHH@Z.arch_sandybridge"(i32 %0) @@ -81,8 +86,8 @@ int bar() { // WINDOWS: call i32 @"?foo@ns@@YAHH@Z.sse4.2"(i32 %0) // WINDOWS: call i32 @"?foo@ns@@YAHH@Z"(i32 %0) -// LINUX: declare noundef i32 @_Z3fooi.arch_sandybridge(i32 noundef) -// LINUX: declare noundef i32 @_ZN2ns3fooEi.arch_sandybridge(i32 noundef) +// ITANIUM: declare noundef i32 @_Z3fooi.arch_sandybridge(i32 noundef) +// ITANIUM: declare noundef i32 @_ZN2ns3fooEi.arch_sandybridge(i32 noundef) // WINDOWS: declare dso_local noundef i32 @"?foo@@YAHH@Z.arch_sandybridge"(i32 noundef) // WINDOWS: declare dso_local noundef i32 @"?foo@ns@@YAHH@Z.arch_sandybridge"(i32 noundef) diff --git a/clang/test/CodeGenCXX/attr-target-mv-func-ptrs.cpp b/clang/test/CodeGenCXX/attr-target-mv-func-ptrs.cpp index 690f44ceb58be..111f6828c4359 100644 --- a/clang/test/CodeGenCXX/attr-target-mv-func-ptrs.cpp +++ b/clang/test/CodeGenCXX/attr-target-mv-func-ptrs.cpp @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -std=c++11 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix=LINUX +// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-macosx -emit-llvm %s -o - | FileCheck %s --check-prefix=LINUX // RUN: %clang_cc1 -std=c++11 -triple x86_64-windows-pc -emit-llvm %s -o - | FileCheck %s --check-prefix=WINDOWS void temp(); void temp(int); diff --git a/clang/test/CodeGenCXX/attr-target-mv-inalloca.cpp b/clang/test/CodeGenCXX/attr-target-mv-inalloca.cpp index 614e44ee6df57..f11ac76ca771d 100644 --- a/clang/test/CodeGenCXX/attr-target-mv-inalloca.cpp +++ b/clang/test/CodeGenCXX/attr-target-mv-inalloca.cpp @@ -1,5 +1,7 @@ // RUN: %clang_cc1 -std=c++11 -triple i686-windows-msvc -emit-llvm %s -o - | FileCheck %s --check-prefix=WINDOWS // RUN: %clang_cc1 -std=c++11 -triple x86_64-windows-msvc -emit-llvm %s -o - | FileCheck %s --check-prefix=WINDOWS64 +// RUN: %clang_cc1 -std=c++11 -triple x86_64-pc-linux -emit-llvm %s -o - | FileCheck %s --check-prefix=LINUX +// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-macosx -emit-llvm %s -o - | FileCheck %s --check-prefix=DARWIN struct Foo { Foo(); @@ -16,6 +18,9 @@ void usage() { bar(f); } +// DARWIN-NOT: inalloca( +// LINUX-NOT: inalloca( + // WINDOWS: define dso_local noundef i32 @"?bar@@YAHUFoo@@@Z"(ptr inalloca(<{ %struct.Foo }>) %0) // WINDOWS: %[[O:[0-9a-zA-Z]+]] = getelementptr inbounds <{ %struct.Foo }>, ptr %0, i32 0, i32 0 // WINDOWS: %[[X:[0-9a-zA-Z]+]] = getelementptr inbounds %struct.Foo, ptr %[[O]], i32 0, i32 0 diff --git a/clang/test/CodeGenCXX/attr-target-mv-member-funcs.cpp b/clang/test/CodeGenCXX/attr-target-mv-member-funcs.cpp index cf3ba290714e0..35a62ee7e773c 100644 --- a/clang/test/CodeGenCXX/attr-target-mv-member-funcs.cpp +++ b/clang/test/CodeGenCXX/attr-target-mv-member-funcs.cpp @@ -1,4 +1,5 @@ -// RUN: %clang_cc1 -std=c++11 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix=LINUX +// RUN: %clang_cc1 -std=c++11 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefixes=ITANIUM,LINUX +// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-macosx -emit-llvm %s -o - | FileCheck %s --check-prefixes=ITANIUM,DARWIN // RUN: %clang_cc1 -std=c++11 -triple x86_64-windows-pc -emit-llvm %s -o - | FileCheck %s --check-prefix=WINDOWS struct S { @@ -65,22 +66,24 @@ int templ_use() { return a.foo(1) + b.foo(2); } -// LINUX: @_ZN1SaSERKS_.ifunc = weak_odr ifunc ptr (ptr, ptr), ptr @_ZN1SaSERKS_.resolver -// LINUX: @_ZNK9ConvertTocv1SEv.ifunc = weak_odr ifunc void (ptr), ptr @_ZNK9ConvertTocv1SEv.resolver -// LINUX: @_ZN1S3fooEi.ifunc = weak_odr ifunc i32 (ptr, i32), ptr @_ZN1S3fooEi.resolver -// LINUX: @_ZN2S23fooEi.ifunc = weak_odr ifunc i32 (ptr, i32), ptr @_ZN2S23fooEi.resolver +// DARWIN-NOT: comdat + +// ITANIUM: @_ZN1SaSERKS_.ifunc = weak_odr ifunc ptr (ptr, ptr), ptr @_ZN1SaSERKS_.resolver +// ITANIUM: @_ZNK9ConvertTocv1SEv.ifunc = weak_odr ifunc void (ptr), ptr @_ZNK9ConvertTocv1SEv.resolver +// ITANIUM: @_ZN1S3fooEi.ifunc = weak_odr ifunc i32 (ptr, i32), ptr @_ZN1S3fooEi.resolver +// ITANIUM: @_ZN2S23fooEi.ifunc = weak_odr ifunc i32 (ptr, i32), ptr @_ZN2S23fooEi.resolver // Templates: -// LINUX: @_ZN5templIiE3fooEi.ifunc = weak_odr ifunc i32 (ptr, i32), ptr @_ZN5templIiE3fooEi.resolver -// LINUX: @_ZN5templIdE3fooEi.ifunc = weak_odr ifunc i32 (ptr, i32), ptr @_ZN5templIdE3fooEi.resolver - -// LINUX: define{{.*}} i32 @_Z3barv() -// LINUX: %s = alloca %struct.S, align 1 -// LINUX: %s2 = alloca %struct.S, align 1 -// LINUX: %C = alloca %struct.ConvertTo, align 1 -// LINUX: call noundef nonnull align 1 dereferenceable(1) ptr @_ZN1SaSERKS_.ifunc(ptr {{[^,]*}} %s2 -// LINUX: call void @_ZNK9ConvertTocv1SEv.ifunc(ptr {{[^,]*}} %C) -// LINUX: call noundef nonnull align 1 dereferenceable(1) ptr @_ZN1SaSERKS_.ifunc(ptr {{[^,]*}} %s2 -// LINUX: call noundef i32 @_ZN1S3fooEi.ifunc(ptr {{[^,]*}} %s, i32 noundef 0) +// ITANIUM: @_ZN5templIiE3fooEi.ifunc = weak_odr ifunc i32 (ptr, i32), ptr @_ZN5templIiE3fooEi.resolver +// ITANIUM: @_ZN5templIdE3fooEi.ifunc = weak_odr ifunc i32 (ptr, i32), ptr @_ZN5templIdE3fooEi.resolver + +// ITANIUM: define{{.*}} i32 @_Z3barv() +// ITANIUM: %s = alloca %struct.S, align 1 +// ITANIUM: %s2 = alloca %struct.S, align 1 +// ITANIUM: %C = alloca %struct.ConvertTo, align 1 +// ITANIUM: call noundef nonnull align 1 dereferenceable(1) ptr @_ZN1SaSERKS_.ifunc(ptr {{[^,]*}} %s2 +// ITANIUM: call void @_ZNK9ConvertTocv1SEv.ifunc(ptr {{[^,]*}} %C) +// ITANIUM: call noundef nonnull align 1 dereferenceable(1) ptr @_ZN1SaSERKS_.ifunc(ptr {{[^,]*}} %s2 +// ITANIUM: call noundef i32 @_ZN1S3fooEi.ifunc(ptr {{[^,]*}} %s, i32 noundef 0) // WINDOWS: define dso_local noundef i32 @"?bar@@YAHXZ"() // WINDOWS: %s = alloca %struct.S, align 1 @@ -91,27 +94,30 @@ int templ_use() { // WINDOWS: call noundef nonnull align 1 dereferenceable(1) ptr @"??4S@@QEAAAEAU0@AEBU0@@Z.resolver"(ptr {{[^,]*}} %s2 // WINDOWS: call noundef i32 @"?foo@S@@QEAAHH@Z.resolver"(ptr {{[^,]*}} %s, i32 noundef 0) -// LINUX: define weak_odr ptr @_ZN1SaSERKS_.resolver() comdat -// LINUX: ret ptr @_ZN1SaSERKS_.arch_ivybridge -// LINUX: ret ptr @_ZN1SaSERKS_ +// ITANIUM: define weak_odr ptr @_ZN1SaSERKS_.resolver() +// LINUX-SAME: comdat +// ITANIUM: ret ptr @_ZN1SaSERKS_.arch_ivybridge +// ITANIUM: ret ptr @_ZN1SaSERKS_ // WINDOWS: define weak_odr dso_local ptr @"??4S@@QEAAAEAU0@AEBU0@@Z.resolver"(ptr %0, ptr %1) // WINDOWS: call ptr @"??4S@@QEAAAEAU0@AEBU0@@Z.arch_ivybridge" // WINDOWS: call ptr @"??4S@@QEAAAEAU0@AEBU0@@Z" -// LINUX: define weak_odr ptr @_ZNK9ConvertTocv1SEv.resolver() comdat -// LINUX: ret ptr @_ZNK9ConvertTocv1SEv.arch_ivybridge -// LINUX: ret ptr @_ZNK9ConvertTocv1SEv +// ITANIUM: define weak_odr ptr @_ZNK9ConvertTocv1SEv.resolver() +// LINUX-SAME: comdat +// ITANIUM: ret ptr @_ZNK9ConvertTocv1SEv.arch_ivybridge +// ITANIUM: ret ptr @_ZNK9ConvertTocv1SEv // WINDOWS: define weak_odr dso_local void @"??BConvertTo@@QEBA?AUS@@XZ.resolver"(ptr %0, ptr %1) // WINDOWS: call void @"??BConvertTo@@QEBA?AUS@@XZ.arch_ivybridge" // WINDOWS: call void @"??BConvertTo@@QEBA?AUS@@XZ" -// LINUX: define weak_odr ptr @_ZN1S3fooEi.resolver() comdat -// LINUX: ret ptr @_ZN1S3fooEi.arch_sandybridge -// LINUX: ret ptr @_ZN1S3fooEi.arch_ivybridge -// LINUX: ret ptr @_ZN1S3fooEi.sse4.2 -// LINUX: ret ptr @_ZN1S3fooEi +// ITANIUM: define weak_odr ptr @_ZN1S3fooEi.resolver() +// LINUX-SAME: comdat +// ITANIUM: ret ptr @_ZN1S3fooEi.arch_sandybridge +// ITANIUM: ret ptr @_ZN1S3fooEi.arch_ivybridge +// ITANIUM: ret ptr @_ZN1S3fooEi.sse4.2 +// ITANIUM: ret ptr @_ZN1S3fooEi // WINDOWS: define weak_odr dso_local i32 @"?foo@S@@QEAAHH@Z.resolver"(ptr %0, i32 %1) // WINDOWS: call i32 @"?foo@S@@QEAAHH@Z.arch_sandybridge" @@ -119,17 +125,18 @@ int templ_use() { // WINDOWS: call i32 @"?foo@S@@QEAAHH@Z.sse4.2" // WINDOWS: call i32 @"?foo@S@@QEAAHH@Z" -// LINUX: define{{.*}} i32 @_Z4bar2v() -// LINUX: call noundef i32 @_ZN2S23fooEi.ifunc +// ITANIUM: define{{.*}} i32 @_Z4bar2v() +// ITANIUM: call noundef i32 @_ZN2S23fooEi.ifunc // WINDOWS: define dso_local noundef i32 @"?bar2@@YAHXZ"() // WINDOWS: call noundef i32 @"?foo@S2@@QEAAHH@Z.resolver" -// LINUX: define weak_odr ptr @_ZN2S23fooEi.resolver() comdat -// LINUX: ret ptr @_ZN2S23fooEi.arch_sandybridge -// LINUX: ret ptr @_ZN2S23fooEi.arch_ivybridge -// LINUX: ret ptr @_ZN2S23fooEi.sse4.2 -// LINUX: ret ptr @_ZN2S23fooEi +// ITANIUM: define weak_odr ptr @_ZN2S23fooEi.resolver() +// LINUX-SAME: comdat +// ITANIUM: ret ptr @_ZN2S23fooEi.arch_sandybridge +// ITANIUM: ret ptr @_ZN2S23fooEi.arch_ivybridge +// ITANIUM: ret ptr @_ZN2S23fooEi.sse4.2 +// ITANIUM: ret ptr @_ZN2S23fooEi // WINDOWS: define weak_odr dso_local i32 @"?foo@S2@@QEAAHH@Z.resolver"(ptr %0, i32 %1) // WINDOWS: call i32 @"?foo@S2@@QEAAHH@Z.arch_sandybridge" @@ -137,27 +144,28 @@ int templ_use() { // WINDOWS: call i32 @"?foo@S2@@QEAAHH@Z.sse4.2" // WINDOWS: call i32 @"?foo@S2@@QEAAHH@Z" -// LINUX: define{{.*}} i32 @_ZN2S23fooEi.sse4.2(ptr {{[^,]*}} %this, i32 noundef %0) -// LINUX: define{{.*}} i32 @_ZN2S23fooEi.arch_ivybridge(ptr {{[^,]*}} %this, i32 noundef %0) -// LINUX: define{{.*}} i32 @_ZN2S23fooEi(ptr {{[^,]*}} %this, i32 noundef %0) +// ITANIUM: define{{.*}} i32 @_ZN2S23fooEi.sse4.2(ptr {{[^,]*}} %this, i32 noundef %0) +// ITANIUM: define{{.*}} i32 @_ZN2S23fooEi.arch_ivybridge(ptr {{[^,]*}} %this, i32 noundef %0) +// ITANIUM: define{{.*}} i32 @_ZN2S23fooEi(ptr {{[^,]*}} %this, i32 noundef %0) // WINDOWS: define dso_local noundef i32 @"?foo@S2@@QEAAHH@Z.sse4.2"(ptr {{[^,]*}} %this, i32 noundef %0) // WINDOWS: define dso_local noundef i32 @"?foo@S2@@QEAAHH@Z.arch_ivybridge"(ptr {{[^,]*}} %this, i32 noundef %0) // WINDOWS: define dso_local noundef i32 @"?foo@S2@@QEAAHH@Z"(ptr {{[^,]*}} %this, i32 noundef %0) -// LINUX: define{{.*}} i32 @_Z9templ_usev() -// LINUX: call noundef i32 @_ZN5templIiE3fooEi.ifunc -// LINUX: call noundef i32 @_ZN5templIdE3fooEi.ifunc +// ITANIUM: define{{.*}} i32 @_Z9templ_usev() +// ITANIUM: call noundef i32 @_ZN5templIiE3fooEi.ifunc +// ITANIUM: call noundef i32 @_ZN5templIdE3fooEi.ifunc // WINDOWS: define dso_local noundef i32 @"?templ_use@@YAHXZ"() // WINDOWS: call noundef i32 @"?foo@?$templ@H@@QEAAHH@Z.resolver" // WINDOWS: call noundef i32 @"?foo@?$templ@N@@QEAAHH@Z.resolver" -// LINUX: define weak_odr ptr @_ZN5templIiE3fooEi.resolver() comdat -// LINUX: ret ptr @_ZN5templIiE3fooEi.arch_sandybridge -// LINUX: ret ptr @_ZN5templIiE3fooEi.arch_ivybridge -// LINUX: ret ptr @_ZN5templIiE3fooEi.sse4.2 -// LINUX: ret ptr @_ZN5templIiE3fooEi +// ITANIUM: define weak_odr ptr @_ZN5templIiE3fooEi.resolver() +// LINUX-SAME: comdat +// ITANIUM: ret ptr @_ZN5templIiE3fooEi.arch_sandybridge +// ITANIUM: ret ptr @_ZN5templIiE3fooEi.arch_ivybridge +// ITANIUM: ret ptr @_ZN5templIiE3fooEi.sse4.2 +// ITANIUM: ret ptr @_ZN5templIiE3fooEi // WINDOWS: define weak_odr dso_local i32 @"?foo@?$templ@H@@QEAAHH@Z.resolver"(ptr %0, i32 %1) // WINDOWS: call i32 @"?foo@?$templ@H@@QEAAHH@Z.arch_sandybridge" @@ -165,11 +173,12 @@ int templ_use() { // WINDOWS: call i32 @"?foo@?$templ@H@@QEAAHH@Z.sse4.2" // WINDOWS: call i32 @"?foo@?$templ@H@@QEAAHH@Z" -// LINUX: define weak_odr ptr @_ZN5templIdE3fooEi.resolver() comdat -// LINUX: ret ptr @_ZN5templIdE3fooEi.arch_sandybridge -// LINUX: ret ptr @_ZN5templIdE3fooEi.arch_ivybridge -// LINUX: ret ptr @_ZN5templIdE3fooEi.sse4.2 -// LINUX: ret ptr @_ZN5templIdE3fooEi +// ITANIUM: define weak_odr ptr @_ZN5templIdE3fooEi.resolver() +// LINUX-SAME: comdat +// ITANIUM: ret ptr @_ZN5templIdE3fooEi.arch_sandybridge +// ITANIUM: ret ptr @_ZN5templIdE3fooEi.arch_ivybridge +// ITANIUM: ret ptr @_ZN5templIdE3fooEi.sse4.2 +// ITANIUM: ret ptr @_ZN5templIdE3fooEi // WINDOWS: define weak_odr dso_local i32 @"?foo@?$templ@N@@QEAAHH@Z.resolver"(ptr %0, i32 %1) comdat // WINDOWS: call i32 @"?foo@?$templ@N@@QEAAHH@Z.arch_sandybridge" @@ -177,42 +186,42 @@ int templ_use() { // WINDOWS: call i32 @"?foo@?$templ@N@@QEAAHH@Z.sse4.2" // WINDOWS: call i32 @"?foo@?$templ@N@@QEAAHH@Z" -// LINUX: define linkonce_odr noundef i32 @_ZN1S3fooEi.sse4.2(ptr {{[^,]*}} %this, i32 noundef %0) -// LINUX: ret i32 0 +// ITANIUM: define linkonce_odr noundef i32 @_ZN1S3fooEi.sse4.2(ptr {{[^,]*}} %this, i32 noundef %0) +// ITANIUM: ret i32 0 // WINDOWS: define linkonce_odr dso_local noundef i32 @"?foo@S@@QEAAHH@Z.sse4.2"(ptr {{[^,]*}} %this, i32 noundef %0) // WINDOWS: ret i32 0 -// LINUX: declare noundef i32 @_ZN1S3fooEi.arch_sandybridge(ptr {{[^,]*}}, i32 noundef) +// ITANIUM: declare noundef i32 @_ZN1S3fooEi.arch_sandybridge(ptr {{[^,]*}}, i32 noundef) // WINDOWS: declare dso_local noundef i32 @"?foo@S@@QEAAHH@Z.arch_sandybridge"(ptr {{[^,]*}}, i32 noundef) -// LINUX: define linkonce_odr noundef i32 @_ZN1S3fooEi.arch_ivybridge(ptr {{[^,]*}} %this, i32 noundef %0) -// LINUX: ret i32 1 +// ITANIUM: define linkonce_odr noundef i32 @_ZN1S3fooEi.arch_ivybridge(ptr {{[^,]*}} %this, i32 noundef %0) +// ITANIUM: ret i32 1 // WINDOWS: define linkonce_odr dso_local noundef i32 @"?foo@S@@QEAAHH@Z.arch_ivybridge"(ptr {{[^,]*}} %this, i32 noundef %0) // WINDOWS: ret i32 1 -// LINUX: define linkonce_odr noundef i32 @_ZN1S3fooEi(ptr {{[^,]*}} %this, i32 noundef %0) -// LINUX: ret i32 2 +// ITANIUM: define linkonce_odr noundef i32 @_ZN1S3fooEi(ptr {{[^,]*}} %this, i32 noundef %0) +// ITANIUM: ret i32 2 // WINDOWS: define linkonce_odr dso_local noundef i32 @"?foo@S@@QEAAHH@Z"(ptr {{[^,]*}} %this, i32 noundef %0) // WINDOWS: ret i32 2 -// LINUX: define linkonce_odr noundef i32 @_ZN5templIiE3fooEi.sse4.2 -// LINUX: declare noundef i32 @_ZN5templIiE3fooEi.arch_sandybridge -// LINUX: define linkonce_odr noundef i32 @_ZN5templIiE3fooEi.arch_ivybridge -// LINUX: define linkonce_odr noundef i32 @_ZN5templIiE3fooEi +// ITANIUM: define linkonce_odr noundef i32 @_ZN5templIiE3fooEi.sse4.2 +// ITANIUM: declare noundef i32 @_ZN5templIiE3fooEi.arch_sandybridge +// ITANIUM: define linkonce_odr noundef i32 @_ZN5templIiE3fooEi.arch_ivybridge +// ITANIUM: define linkonce_odr noundef i32 @_ZN5templIiE3fooEi // WINDOWS: define linkonce_odr dso_local noundef i32 @"?foo@?$templ@H@@QEAAHH@Z.sse4.2" // WINDOWS: declare dso_local noundef i32 @"?foo@?$templ@H@@QEAAHH@Z.arch_sandybridge" // WINDOWS: define linkonce_odr dso_local noundef i32 @"?foo@?$templ@H@@QEAAHH@Z.arch_ivybridge" // WINDOWS: define linkonce_odr dso_local noundef i32 @"?foo@?$templ@H@@QEAAHH@Z" -// LINUX: define linkonce_odr noundef i32 @_ZN5templIdE3fooEi.sse4.2 -// LINUX: declare noundef i32 @_ZN5templIdE3fooEi.arch_sandybridge -// LINUX: define linkonce_odr noundef i32 @_ZN5templIdE3fooEi.arch_ivybridge -// LINUX: define linkonce_odr noundef i32 @_ZN5templIdE3fooEi +// ITANIUM: define linkonce_odr noundef i32 @_ZN5templIdE3fooEi.sse4.2 +// ITANIUM: declare noundef i32 @_ZN5templIdE3fooEi.arch_sandybridge +// ITANIUM: define linkonce_odr noundef i32 @_ZN5templIdE3fooEi.arch_ivybridge +// ITANIUM: define linkonce_odr noundef i32 @_ZN5templIdE3fooEi // WINDOWS: define linkonce_odr dso_local noundef i32 @"?foo@?$templ@N@@QEAAHH@Z.sse4.2" // WINDOWS: declare dso_local noundef i32 @"?foo@?$templ@N@@QEAAHH@Z.arch_sandybridge" diff --git a/clang/test/CodeGenCXX/attr-target-mv-modules.cpp b/clang/test/CodeGenCXX/attr-target-mv-modules.cpp index c91cf71fc5f8d..3a70e270e9a38 100644 --- a/clang/test/CodeGenCXX/attr-target-mv-modules.cpp +++ b/clang/test/CodeGenCXX/attr-target-mv-modules.cpp @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -std=c++11 -triple x86_64-linux-gnu -fmodules -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-macosx -fmodules -emit-llvm %s -o - | FileCheck %s #pragma clang module build A module A {} #pragma clang module contents diff --git a/clang/test/CodeGenCXX/attr-target-mv-out-of-line-defs.cpp b/clang/test/CodeGenCXX/attr-target-mv-out-of-line-defs.cpp index dda7de08aed43..b81897afb90b8 100644 --- a/clang/test/CodeGenCXX/attr-target-mv-out-of-line-defs.cpp +++ b/clang/test/CodeGenCXX/attr-target-mv-out-of-line-defs.cpp @@ -1,4 +1,5 @@ -// RUN: %clang_cc1 -std=c++11 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix=LINUX +// RUN: %clang_cc1 -std=c++11 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefixes=ITANIUM,LINUX +// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-macosx -emit-llvm %s -o - | FileCheck %s --check-prefixes=ITANIUM,DARWIN // RUN: %clang_cc1 -std=c++11 -triple x86_64-windows-pc -emit-llvm %s -o - | FileCheck %s --check-prefix=WINDOWS struct S { int __attribute__((target("sse4.2"))) foo(int); @@ -16,39 +17,42 @@ int bar() { return s.foo(0); } -// LINUX: @_ZN1S3fooEi.ifunc = weak_odr ifunc i32 (ptr, i32), ptr @_ZN1S3fooEi.resolver +// DARWIN-NOT: comdat -// LINUX: define{{.*}} i32 @_ZN1S3fooEi(ptr {{[^,]*}} %this, i32 noundef %0) -// LINUX: ret i32 2 +// ITANIUM: @_ZN1S3fooEi.ifunc = weak_odr ifunc i32 (ptr, i32), ptr @_ZN1S3fooEi.resolver + +// ITANIUM: define{{.*}} i32 @_ZN1S3fooEi(ptr {{[^,]*}} %this, i32 noundef %0) +// ITANIUM: ret i32 2 // WINDOWS: define dso_local noundef i32 @"?foo@S@@QEAAHH@Z"(ptr {{[^,]*}} %this, i32 noundef %0) // WINDOWS: ret i32 2 -// LINUX: define{{.*}} i32 @_ZN1S3fooEi.sse4.2(ptr {{[^,]*}} %this, i32 noundef %0) -// LINUX: ret i32 0 +// ITANIUM: define{{.*}} i32 @_ZN1S3fooEi.sse4.2(ptr {{[^,]*}} %this, i32 noundef %0) +// ITANIUM: ret i32 0 // WINDOWS: define dso_local noundef i32 @"?foo@S@@QEAAHH@Z.sse4.2"(ptr {{[^,]*}} %this, i32 noundef %0) // WINDOWS: ret i32 0 -// LINUX: define{{.*}} i32 @_ZN1S3fooEi.arch_ivybridge(ptr {{[^,]*}} %this, i32 noundef %0) -// LINUX: ret i32 1 +// ITANIUM: define{{.*}} i32 @_ZN1S3fooEi.arch_ivybridge(ptr {{[^,]*}} %this, i32 noundef %0) +// ITANIUM: ret i32 1 // WINDOWS: define dso_local noundef i32 @"?foo@S@@QEAAHH@Z.arch_ivybridge"(ptr {{[^,]*}} %this, i32 noundef %0) // WINDOWS: ret i32 1 -// LINUX: define{{.*}} i32 @_Z3barv() -// LINUX: %s = alloca %struct.S, align 1 -// LINUX: %call = call noundef i32 @_ZN1S3fooEi.ifunc(ptr {{[^,]*}} %s, i32 noundef 0) +// ITANIUM: define{{.*}} i32 @_Z3barv() +// ITANIUM: %s = alloca %struct.S, align 1 +// ITANIUM: %call = call noundef i32 @_ZN1S3fooEi.ifunc(ptr {{[^,]*}} %s, i32 noundef 0) // WINDOWS: define dso_local noundef i32 @"?bar@@YAHXZ"() // WINDOWS: %s = alloca %struct.S, align 1 // WINDOWS: %call = call noundef i32 @"?foo@S@@QEAAHH@Z.resolver"(ptr {{[^,]*}} %s, i32 noundef 0) -// LINUX: define weak_odr ptr @_ZN1S3fooEi.resolver() comdat -// LINUX: ret ptr @_ZN1S3fooEi.arch_sandybridge -// LINUX: ret ptr @_ZN1S3fooEi.arch_ivybridge -// LINUX: ret ptr @_ZN1S3fooEi.sse4.2 -// LINUX: ret ptr @_ZN1S3fooEi +// ITANIUM: define weak_odr ptr @_ZN1S3fooEi.resolver() +// LINUX-SAME: comdat +// ITANIUM: ret ptr @_ZN1S3fooEi.arch_sandybridge +// ITANIUM: ret ptr @_ZN1S3fooEi.arch_ivybridge +// ITANIUM: ret ptr @_ZN1S3fooEi.sse4.2 +// ITANIUM: ret ptr @_ZN1S3fooEi // WINDOWS: define weak_odr dso_local i32 @"?foo@S@@QEAAHH@Z.resolver"(ptr %0, i32 %1) comdat // WINDOWS: call i32 @"?foo@S@@QEAAHH@Z.arch_sandybridge"(ptr %0, i32 %1) @@ -56,6 +60,6 @@ int bar() { // WINDOWS: call i32 @"?foo@S@@QEAAHH@Z.sse4.2"(ptr %0, i32 %1) // WINDOWS: call i32 @"?foo@S@@QEAAHH@Z"(ptr %0, i32 %1) -// LINUX: declare noundef i32 @_ZN1S3fooEi.arch_sandybridge(ptr {{[^,]*}}, i32 noundef) +// ITANIUM: declare noundef i32 @_ZN1S3fooEi.arch_sandybridge(ptr {{[^,]*}}, i32 noundef) // WINDOWS: declare dso_local noundef i32 @"?foo@S@@QEAAHH@Z.arch_sandybridge"(ptr {{[^,]*}}, i32 noundef) diff --git a/clang/test/CodeGenCXX/attr-target-mv-overloads.cpp b/clang/test/CodeGenCXX/attr-target-mv-overloads.cpp index 49a05e7485a5d..dddd8981954e3 100644 --- a/clang/test/CodeGenCXX/attr-target-mv-overloads.cpp +++ b/clang/test/CodeGenCXX/attr-target-mv-overloads.cpp @@ -1,4 +1,5 @@ -// RUN: %clang_cc1 -std=c++11 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix=LINUX +// RUN: %clang_cc1 -std=c++11 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefixes=ITANIUM,LINUX +// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-macosx -emit-llvm %s -o - | FileCheck %s --check-prefixes=ITANIUM,DARWIN // RUN: %clang_cc1 -std=c++11 -triple x86_64-windows-pc -emit-llvm %s -o - | FileCheck %s --check-prefix=WINDOWS int __attribute__((target("sse4.2"))) foo_overload(int) { return 0; } @@ -14,21 +15,23 @@ int bar2() { return foo_overload() + foo_overload(1); } -// LINUX: @_Z12foo_overloadv.ifunc = weak_odr ifunc i32 (), ptr @_Z12foo_overloadv.resolver -// LINUX: @_Z12foo_overloadi.ifunc = weak_odr ifunc i32 (i32), ptr @_Z12foo_overloadi.resolver +// DARWIN-NOT: comdat -// LINUX: define{{.*}} i32 @_Z12foo_overloadi.sse4.2(i32 noundef %0) -// LINUX: ret i32 0 -// LINUX: define{{.*}} i32 @_Z12foo_overloadi.arch_ivybridge(i32 noundef %0) -// LINUX: ret i32 1 -// LINUX: define{{.*}} i32 @_Z12foo_overloadi(i32 noundef %0) -// LINUX: ret i32 2 -// LINUX: define{{.*}} i32 @_Z12foo_overloadv.sse4.2() -// LINUX: ret i32 0 -// LINUX: define{{.*}} i32 @_Z12foo_overloadv.arch_ivybridge() -// LINUX: ret i32 1 -// LINUX: define{{.*}} i32 @_Z12foo_overloadv() -// LINUX: ret i32 2 +// ITANIUM: @_Z12foo_overloadv.ifunc = weak_odr ifunc i32 (), ptr @_Z12foo_overloadv.resolver +// ITANIUM: @_Z12foo_overloadi.ifunc = weak_odr ifunc i32 (i32), ptr @_Z12foo_overloadi.resolver + +// ITANIUM: define{{.*}} i32 @_Z12foo_overloadi.sse4.2(i32 noundef %0) +// ITANIUM: ret i32 0 +// ITANIUM: define{{.*}} i32 @_Z12foo_overloadi.arch_ivybridge(i32 noundef %0) +// ITANIUM: ret i32 1 +// ITANIUM: define{{.*}} i32 @_Z12foo_overloadi(i32 noundef %0) +// ITANIUM: ret i32 2 +// ITANIUM: define{{.*}} i32 @_Z12foo_overloadv.sse4.2() +// ITANIUM: ret i32 0 +// ITANIUM: define{{.*}} i32 @_Z12foo_overloadv.arch_ivybridge() +// ITANIUM: ret i32 1 +// ITANIUM: define{{.*}} i32 @_Z12foo_overloadv() +// ITANIUM: ret i32 2 // WINDOWS: define dso_local noundef i32 @"?foo_overload@@YAHH@Z.sse4.2"(i32 noundef %0) // WINDOWS: ret i32 0 @@ -43,19 +46,20 @@ int bar2() { // WINDOWS: define dso_local noundef i32 @"?foo_overload@@YAHXZ"() // WINDOWS: ret i32 2 -// LINUX: define{{.*}} i32 @_Z4bar2v() -// LINUX: call noundef i32 @_Z12foo_overloadv.ifunc() -// LINUX: call noundef i32 @_Z12foo_overloadi.ifunc(i32 noundef 1) +// ITANIUM: define{{.*}} i32 @_Z4bar2v() +// ITANIUM: call noundef i32 @_Z12foo_overloadv.ifunc() +// ITANIUM: call noundef i32 @_Z12foo_overloadi.ifunc(i32 noundef 1) // WINDOWS: define dso_local noundef i32 @"?bar2@@YAHXZ"() // WINDOWS: call noundef i32 @"?foo_overload@@YAHXZ.resolver"() // WINDOWS: call noundef i32 @"?foo_overload@@YAHH@Z.resolver"(i32 noundef 1) -// LINUX: define weak_odr ptr @_Z12foo_overloadv.resolver() comdat -// LINUX: ret ptr @_Z12foo_overloadv.arch_sandybridge -// LINUX: ret ptr @_Z12foo_overloadv.arch_ivybridge -// LINUX: ret ptr @_Z12foo_overloadv.sse4.2 -// LINUX: ret ptr @_Z12foo_overloadv +// ITANIUM: define weak_odr ptr @_Z12foo_overloadv.resolver() +// LINUX-SAME: comdat +// ITANIUM: ret ptr @_Z12foo_overloadv.arch_sandybridge +// ITANIUM: ret ptr @_Z12foo_overloadv.arch_ivybridge +// ITANIUM: ret ptr @_Z12foo_overloadv.sse4.2 +// ITANIUM: ret ptr @_Z12foo_overloadv // WINDOWS: define weak_odr dso_local i32 @"?foo_overload@@YAHXZ.resolver"() comdat // WINDOWS: call i32 @"?foo_overload@@YAHXZ.arch_sandybridge" @@ -63,11 +67,12 @@ int bar2() { // WINDOWS: call i32 @"?foo_overload@@YAHXZ.sse4.2" // WINDOWS: call i32 @"?foo_overload@@YAHXZ" -// LINUX: define weak_odr ptr @_Z12foo_overloadi.resolver() comdat -// LINUX: ret ptr @_Z12foo_overloadi.arch_sandybridge -// LINUX: ret ptr @_Z12foo_overloadi.arch_ivybridge -// LINUX: ret ptr @_Z12foo_overloadi.sse4.2 -// LINUX: ret ptr @_Z12foo_overloadi +// ITANIUM: define weak_odr ptr @_Z12foo_overloadi.resolver() +// LINUX-SAME: comdat +// ITANIUM: ret ptr @_Z12foo_overloadi.arch_sandybridge +// ITANIUM: ret ptr @_Z12foo_overloadi.arch_ivybridge +// ITANIUM: ret ptr @_Z12foo_overloadi.sse4.2 +// ITANIUM: ret ptr @_Z12foo_overloadi // WINDOWS: define weak_odr dso_local i32 @"?foo_overload@@YAHH@Z.resolver"(i32 %0) comdat // WINDOWS: call i32 @"?foo_overload@@YAHH@Z.arch_sandybridge" @@ -75,8 +80,8 @@ int bar2() { // WINDOWS: call i32 @"?foo_overload@@YAHH@Z.sse4.2" // WINDOWS: call i32 @"?foo_overload@@YAHH@Z" -// LINUX: declare noundef i32 @_Z12foo_overloadv.arch_sandybridge() -// LINUX: declare noundef i32 @_Z12foo_overloadi.arch_sandybridge(i32 noundef) +// ITANIUM: declare noundef i32 @_Z12foo_overloadv.arch_sandybridge() +// ITANIUM: declare noundef i32 @_Z12foo_overloadi.arch_sandybridge(i32 noundef) // WINDOWS: declare dso_local noundef i32 @"?foo_overload@@YAHXZ.arch_sandybridge"() // WINDOWS: declare dso_local noundef i32 @"?foo_overload@@YAHH@Z.arch_sandybridge"(i32 noundef) diff --git a/clang/test/CodeGenCXX/externc-ifunc-resolver.cpp b/clang/test/CodeGenCXX/externc-ifunc-resolver.cpp index 0518a8dcc831d..be4453ae7eb08 100644 --- a/clang/test/CodeGenCXX/externc-ifunc-resolver.cpp +++ b/clang/test/CodeGenCXX/externc-ifunc-resolver.cpp @@ -1,4 +1,6 @@ // RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-apple-macosx -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple arm64-apple-macosx -emit-llvm -o - %s | FileCheck %s extern "C" { __attribute__((used)) static void *resolve_foo() { return 0; } diff --git a/clang/test/SemaCXX/externc-ifunc-resolver.cpp b/clang/test/SemaCXX/externc-ifunc-resolver.cpp index aa44525bde2ca..6c6c262c5f09d 100644 --- a/clang/test/SemaCXX/externc-ifunc-resolver.cpp +++ b/clang/test/SemaCXX/externc-ifunc-resolver.cpp @@ -1,5 +1,9 @@ // RUN: %clang_cc1 -emit-llvm-only -triple x86_64-linux-gnu -verify %s +// RUN: %clang_cc1 -emit-llvm-only -triple x86_64-apple-macosx -verify %s +// RUN: %clang_cc1 -emit-llvm-only -triple arm64-apple-macosx -verify %s // RUN: not %clang_cc1 -triple x86_64-linux -emit-llvm-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s +// RUN: not %clang_cc1 -triple x86_64-apple-macosx -emit-llvm-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s +// RUN: not %clang_cc1 -triple arm64-apple-macosx -emit-llvm-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s extern "C" { __attribute__((used)) static void *resolve_foo() { return 0; } From 97e7926f25d81fb6c6d87202f721c2e2cf6198f5 Mon Sep 17 00:00:00 2001 From: Jon Roelofs Date: Wed, 29 Nov 2023 13:57:10 -0800 Subject: [PATCH 06/13] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20?= =?UTF-8?q?changes=20introduced=20through=20rebase?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Created using spr 1.3.4 [skip ci] --- clang/include/clang/Basic/AttrDocs.td | 6 +++--- clang/test/CodeGen/ifunc.c | 4 ++++ llvm/docs/LangRef.rst | 2 +- llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 2 +- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 4c4c4eb606fb0..5e85ec52a4634 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -5408,9 +5408,9 @@ considered inline. Not all targets support this attribute. ELF target support depends on both the linker and runtime linker, and is available in at least lld 4.0 and later, binutils 2.20.1 and later, glibc v2.11.1 and later, and FreeBSD 9.1 and later. -MachO targets support it, but with slightly different semantics: the resolver is -run at first call, instead of at load time by the runtime linker. Targets other -than ELF and MachO currently do not support this attribute. +Mach-O targets support it, but with slightly different semantics: the resolver +is run at first call, instead of at load time by the runtime linker. Targets +other than ELF and Mach-O currently do not support this attribute. }]; } diff --git a/clang/test/CodeGen/ifunc.c b/clang/test/CodeGen/ifunc.c index 99d60dc0ea85d..a29b500e80bd5 100644 --- a/clang/test/CodeGen/ifunc.c +++ b/clang/test/CodeGen/ifunc.c @@ -3,9 +3,13 @@ // RUN: %clang_cc1 -triple i386-unknown-linux-gnu -fsanitize=thread -O2 -emit-llvm -o - %s | FileCheck %s --check-prefix=SAN // RUN: %clang_cc1 -triple i386-unknown-linux-gnu -fsanitize=address -O2 -emit-llvm -o - %s | FileCheck %s --check-prefix=SAN // RUN: %clang_cc1 -triple i386-unknown-linux-gnu -fsanitize=memory -O2 -emit-llvm -o - %s | FileCheck %s --check-prefix=SAN +// RUN: %clang_cc1 -triple arm64-apple-macosx -emit-llvm -o - %s | FileCheck %s // RUN: %clang_cc1 -triple x86_64-apple-macosx -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple arm64-apple-macosx -O2 -emit-llvm -o - %s | FileCheck %s // RUN: %clang_cc1 -triple x86_64-apple-macosx -O2 -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple arm64-apple-macosx -fsanitize=thread -O2 -emit-llvm -o - %s | FileCheck %s --check-prefix=MACSAN // RUN: %clang_cc1 -triple x86_64-apple-macosx -fsanitize=thread -O2 -emit-llvm -o - %s | FileCheck %s --check-prefix=MACSAN +// RUN: %clang_cc1 -triple arm64-apple-macosx -fsanitize=address -O2 -emit-llvm -o - %s | FileCheck %s --check-prefix=MACSAN // RUN: %clang_cc1 -triple x86_64-apple-macosx -fsanitize=address -O2 -emit-llvm -o - %s | FileCheck %s --check-prefix=MACSAN int foo(int) __attribute__ ((ifunc("foo_ifunc"))); diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst index cb222e979db29..fece4ac7f127d 100644 --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -937,7 +937,7 @@ IFuncs, like as aliases, don't create any new data or func. They are just a new symbol that is resolved at runtime by calling a resolver function. On ELF platforms, IFuncs are resolved by the dynamic linker at load time. On -MachO platforms, they are lowered in terms of ``.symbol_resolver``s, which +Mach-O platforms, they are lowered in terms of ``.symbol_resolver``s, which lazily resolve the callee the first time they are called. IFunc may have an optional :ref:`linkage type ` and an optional diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index b4ac0a70e7fde..aaa7693c61f0e 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -2321,7 +2321,7 @@ bool AsmPrinter::doFinalization(Module &M) { } // IFuncs must come before deubginfo in case the backend decides to emit them - // as actual functions, since on MachO targets, we cannot create regular + // as actual functions, since on Mach-O targets, we cannot create regular // sections after DWARF. for (const auto &IFunc : M.ifuncs()) emitGlobalIFunc(M, IFunc); From b3ed2e9abc371f37b35f77d4d7f93d4673e5f333 Mon Sep 17 00:00:00 2001 From: Jon Roelofs Date: Wed, 29 Nov 2023 14:08:05 -0800 Subject: [PATCH 07/13] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20?= =?UTF-8?q?changes=20introduced=20through=20rebase?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Created using spr 1.3.4 [skip ci] --- llvm/docs/LangRef.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst index fece4ac7f127d..51c60ecf5ac65 100644 --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -937,8 +937,8 @@ IFuncs, like as aliases, don't create any new data or func. They are just a new symbol that is resolved at runtime by calling a resolver function. On ELF platforms, IFuncs are resolved by the dynamic linker at load time. On -Mach-O platforms, they are lowered in terms of ``.symbol_resolver``s, which -lazily resolve the callee the first time they are called. +Mach-O platforms, they are lowered in terms of ``.symbol_resolver`` functions, +which lazily resolve the callee the first time they are called. IFunc may have an optional :ref:`linkage type ` and an optional :ref:`visibility style `. From 603983e237e73b2d939bf9ee12e39ecc7983f7f1 Mon Sep 17 00:00:00 2001 From: Jon Roelofs Date: Wed, 29 Nov 2023 14:21:54 -0800 Subject: [PATCH 08/13] add a note about the dispatch_once block Created using spr 1.3.4 --- compiler-rt/lib/builtins/cpu_model.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/compiler-rt/lib/builtins/cpu_model.c b/compiler-rt/lib/builtins/cpu_model.c index 5f5182859080c..001467a9f7ff5 100644 --- a/compiler-rt/lib/builtins/cpu_model.c +++ b/compiler-rt/lib/builtins/cpu_model.c @@ -1285,6 +1285,14 @@ static bool isKnownAndSupported(const char *name) { } void __init_cpu_features_resolver(void) { + // On Darwin platforms, this may be called concurrently by multiple threads + // because the resolvers that use it are called lazily at runtime (unlike on + // ELF platforms, where IFuncs are resolved serially at load time). This + // function's effect on __aarch64_cpu_features should be idempotent, but even + // so we need dispatch_once to resolve the race condition. Dispatch is + // available through libSystem, which we need anyway for the sysctl, so this + // does not add a new dependency. + static dispatch_once_t onceToken = 0; dispatch_once(&onceToken, ^{ // https://developer.apple.com/documentation/kernel/1387446-sysctlbyname/determining_instruction_set_characteristics From cbb161112cf62e0cd0b67d9be8b02f640d6178b4 Mon Sep 17 00:00:00 2001 From: Jon Roelofs Date: Wed, 29 Nov 2023 15:19:31 -0800 Subject: [PATCH 09/13] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20?= =?UTF-8?q?changes=20introduced=20through=20rebase?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Created using spr 1.3.4 [skip ci] --- llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp | 1 + llvm/lib/Target/X86/X86AsmPrinter.cpp | 1 + llvm/test/CodeGen/AArch64/ifunc-asm.ll | 1 + llvm/test/CodeGen/X86/ifunc-asm.ll | 1 + 4 files changed, 4 insertions(+) diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp index 1b5b7c556c79f..a3513ca439ac2 100644 --- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp +++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp @@ -1905,6 +1905,7 @@ void AArch64AsmPrinter::emitManualSymbolResolver(Module &M, // .quad _ifunc.stub_helper EmitLinkage(LazyPointer); + OutStreamer->emitValueToAlignment(Align(8), /*Value=*/0); OutStreamer->emitLabel(LazyPointer); emitVisibility(LazyPointer, GI.getVisibility()); OutStreamer->emitValue(MCSymbolRefExpr::create(StubHelper, OutContext), 8); diff --git a/llvm/lib/Target/X86/X86AsmPrinter.cpp b/llvm/lib/Target/X86/X86AsmPrinter.cpp index b0f4b9d984372..a490d775abd55 100644 --- a/llvm/lib/Target/X86/X86AsmPrinter.cpp +++ b/llvm/lib/Target/X86/X86AsmPrinter.cpp @@ -558,6 +558,7 @@ void X86AsmPrinter::emitGlobalIFunc(Module &M, const GlobalIFunc &GI) { // .quad _ifunc.stub_helper EmitLinkage(LazyPointer); + OutStreamer->emitValueToAlignment(Align(8), /*Value=*/0); OutStreamer->emitLabel(LazyPointer); emitVisibility(LazyPointer, GI.getVisibility()); OutStreamer->emitValue(MCSymbolRefExpr::create(StubHelper, OutContext), 8); diff --git a/llvm/test/CodeGen/AArch64/ifunc-asm.ll b/llvm/test/CodeGen/AArch64/ifunc-asm.ll index ede669aa52703..7eff692da83ff 100644 --- a/llvm/test/CodeGen/AArch64/ifunc-asm.ll +++ b/llvm/test/CodeGen/AArch64/ifunc-asm.ll @@ -35,6 +35,7 @@ entry: ; MACHO-MANUAL: .section __DATA,__data ; MACHO-MANUAL-NEXT: .globl _global_ifunc.lazy_pointer +; MACHO-MANUAL-NEXT: .p2align 3, 0x0 ; MACHO-MANUAL-NEXT: _global_ifunc.lazy_pointer: ; MACHO-MANUAL-NEXT: .quad _global_ifunc.stub_helper diff --git a/llvm/test/CodeGen/X86/ifunc-asm.ll b/llvm/test/CodeGen/X86/ifunc-asm.ll index 0f66febbe95b2..39c326bc6b6c3 100644 --- a/llvm/test/CodeGen/X86/ifunc-asm.ll +++ b/llvm/test/CodeGen/X86/ifunc-asm.ll @@ -19,6 +19,7 @@ entry: ; MACHO: .section __DATA,__data ; MACHO-NEXT: .globl _foo_ifunc.lazy_pointer +; MACHO-NEXT: .p2align 3, 0x0 ; MACHO-NEXT: _foo_ifunc.lazy_pointer: ; MACHO-NEXT: .quad _foo_ifunc.stub_helper ; MACHO-NEXT: .section __TEXT,__text,regular,pure_instructions From 501007c36f8f5a92bc64aaf54038cc6fb26fa897 Mon Sep 17 00:00:00 2001 From: Jon Roelofs Date: Fri, 1 Dec 2023 13:10:21 -0800 Subject: [PATCH 10/13] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20?= =?UTF-8?q?changes=20introduced=20through=20rebase?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Created using spr 1.3.4 [skip ci] --- llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp | 220 ++++++------------ llvm/test/CodeGen/AArch64/ifunc-asm.ll | 126 +++++----- 2 files changed, 128 insertions(+), 218 deletions(-) diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp index a3513ca439ac2..f19dcb5be1722 100644 --- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp +++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp @@ -71,27 +71,6 @@ using namespace llvm; namespace { -enum class IFuncLowering { - SymbolResolverIfSupported, - SymbolResolverAlways, - SymbolResolverNever -}; - -static cl::opt PreferredIFuncLowering( - "arm64-darwin-ifunc-symbol_resolver", - cl::init(IFuncLowering::SymbolResolverNever), - cl::desc("Pick the lowering for ifuncs on darwin platforms"), cl::Hidden, - cl::values( - clEnumValN( - IFuncLowering::SymbolResolverIfSupported, "if_supported", - "Use .symbol_resolver's when known to be supported by the linker."), - clEnumValN(IFuncLowering::SymbolResolverAlways, "always", - "Always use .symbol_resolvers. NOTE: this might not be " - "supported by the linker in all cases."), - clEnumValN(IFuncLowering::SymbolResolverNever, "never", - "Use a manual lowering, doing what the linker would have " - "done, but in the compiler."))); - class AArch64AsmPrinter : public AsmPrinter { AArch64MCInstLower MCInstLowering; FaultMaps FM; @@ -224,9 +203,6 @@ class AArch64AsmPrinter : public AsmPrinter { } void emitGlobalIFunc(Module &M, const GlobalIFunc &GI) override; - - void emitLinkerSymbolResolver(Module &M, const GlobalIFunc &GI); - void emitManualSymbolResolver(Module &M, const GlobalIFunc &GI); }; } // end anonymous namespace @@ -1838,51 +1814,26 @@ void AArch64AsmPrinter::emitInstruction(const MachineInstr *MI) { EmitToStreamer(*OutStreamer, TmpInst); } -void AArch64AsmPrinter::emitLinkerSymbolResolver(Module &M, - const GlobalIFunc &GI) { - OutStreamer->switchSection(OutContext.getObjectFileInfo()->getTextSection()); - - MCSymbol *Name = getSymbol(&GI); - - // NOTE: non-global .symbol_resolvers are not yet supported by Darwin linkers - - if (GI.hasExternalLinkage() || !MAI->getWeakRefDirective()) - OutStreamer->emitSymbolAttribute(Name, MCSA_Global); - else if (GI.hasWeakLinkage() || GI.hasLinkOnceLinkage()) - OutStreamer->emitSymbolAttribute(Name, MCSA_WeakReference); - else - assert(GI.hasLocalLinkage() && "Invalid ifunc linkage"); - - OutStreamer->emitCodeAlignment(Align(4), STI); - OutStreamer->emitLabel(Name); - OutStreamer->emitSymbolAttribute(Name, MCSA_SymbolResolver); - emitVisibility(Name, GI.getVisibility()); +void AArch64AsmPrinter::emitGlobalIFunc(Module &M, const GlobalIFunc &GI) { + if (!TM.getTargetTriple().isOSBinFormatMachO()) + return AsmPrinter::emitGlobalIFunc(M, GI); - // ld-prime does not seem to support aliases of symbol resolvers, so we have - // to tail call the resolver manually. - OutStreamer->emitInstruction( - MCInstBuilder(AArch64::B) - .addOperand(MCOperand::createExpr(lowerConstant(GI.getResolver()))), - *STI); -} + // On Darwin platforms, emit a manually-constructed .symbol_resolver that + // implements the symbol resolution duties of the IFunc. + // + // Normally, this would be handled by linker magic, but unfortunately there are + // a few limitations in ld64 and ld-prime's implementation of .symbol_resolver + // that mean we can't always use them: + // + // * resolvers cannot be the target of an alias + // * resolvers cannot have private linkage + // * resolvers cannot have linkonce linkage + // * resolvers cannot appear in executables + // * resolvers cannot appear in bundles + // + // This works around that by emitting a close approximation of what the linker + // would have done. -/// \brief Emit a manually-constructed .symbol_resolver that implements the -/// symbol resolution duties of the IFunc. -/// -/// Normally, this would be handled by linker magic, but unfortunately there are -/// a few limitations in ld64 and ld-prime's implementation of .symbol_resolver -/// that mean we can't always use them: -/// -/// * resolvers cannot be the target of an alias -/// * resolvers cannot have private linkage -/// * resolvers cannot have linkonce linkage -/// * resolvers cannot appear in executables -/// * resolvers cannot appear in bundles -/// -/// This works around that by emitting a close approximation of what the linker -/// would have done. -void AArch64AsmPrinter::emitManualSymbolResolver(Module &M, - const GlobalIFunc &GI) { auto EmitLinkage = [&](MCSymbol *Sym) { if (GI.hasExternalLinkage() || !MAI->getWeakRefDirective()) OutStreamer->emitSymbolAttribute(Sym, MCSA_Global); @@ -1964,33 +1915,35 @@ void AArch64AsmPrinter::emitManualSymbolResolver(Module &M, .addReg(AArch64::X16), *STI); + // These stub helpers are only ever called once, so here we're optimizing for + // minimum size by using the pre-indexed store variants, which saves a few + // bytes of instructions to bump & restore sp. + // _ifunc.stub_helper: - // stp fp, lr, [sp, #-16] - // sub fp, sp, 16 - // stp x1, x0, [sp, #-32] - // stp x3, x2, [sp, #-48] - // stp x5, x4, [sp, #-64] - // stp x7, x6, [sp, #-80] - // stp d1, d0, [sp, #-96] - // stp d3, d2, [sp, #-112] - // stp d5, d4, [sp, #-128] - // stp d7, d6, [sp, #-144] - // sub sp, sp, 144 + // stp fp, lr, [sp, #-16]! + // mov fp, sp + // stp x1, x0, [sp, #-16]! + // stp x3, x2, [sp, #-16]! + // stp x5, x4, [sp, #-16]! + // stp x7, x6, [sp, #-16]! + // stp d1, d0, [sp, #-16]! + // stp d3, d2, [sp, #-16]! + // stp d5, d4, [sp, #-16]! + // stp d7, d6, [sp, #-16]! // bl _resolver // adrp x16, lazy_pointer@GOTPAGE // ldr x16, [x16, lazy_pointer@GOTPAGEOFF] // str x0, [x16] // mov x16, x0 - // add sp, sp, 144 - // ldp d7, d6, [sp, #-144] - // ldp d5, d4, [sp, #-128] - // ldp d3, d2, [sp, #-112] - // ldp d1, d0, [sp, #-96] - // ldp x7, x6, [sp, #-80] - // ldp x5, x4, [sp, #-64] - // ldp x3, x2, [sp, #-48] - // ldp x1, x0, [sp, #-32] - // ldp fp, lr, [sp, #-16] + // ldp d7, d6, [sp], #16 + // ldp d5, d4, [sp], #16 + // ldp d3, d2, [sp], #16 + // ldp d1, d0, [sp], #16 + // ldp x7, x6, [sp], #16 + // ldp x5, x4, [sp], #16 + // ldp x3, x2, [sp], #16 + // ldp x1, x0, [sp], #16 + // ldp fp, lr, [sp], #16 // br x16 EmitLinkage(StubHelper); @@ -1998,43 +1951,39 @@ void AArch64AsmPrinter::emitManualSymbolResolver(Module &M, OutStreamer->emitLabel(StubHelper); emitVisibility(StubHelper, GI.getVisibility()); - OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPXi) + OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPXpre) + .addReg(AArch64::SP) .addReg(AArch64::FP) .addReg(AArch64::LR) .addReg(AArch64::SP) .addImm(-2), *STI); - OutStreamer->emitInstruction(MCInstBuilder(AArch64::SUBXri) + OutStreamer->emitInstruction(MCInstBuilder(AArch64::ADDXri) .addReg(AArch64::FP) .addReg(AArch64::SP) - .addImm(16) + .addImm(0) .addImm(0), *STI); - for (int I = 0; I != 8; I += 2) - OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPXi) - .addReg(AArch64::X1 + I) - .addReg(AArch64::X0 + I) + for (int I = 0; I != 4; ++I) + OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPXpre) .addReg(AArch64::SP) - .addImm(-4 - I), + .addReg(AArch64::X1 + 2 * I) + .addReg(AArch64::X0 + 2 * I) + .addReg(AArch64::SP) + .addImm(-2), *STI); - for (int I = 0; I != 8; I += 2) - OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPDi) - .addReg(AArch64::D1 + I) - .addReg(AArch64::D0 + I) + for (int I = 0; I != 4; ++I) + OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPDpre) + .addReg(AArch64::SP) + .addReg(AArch64::D1 + 2 * I) + .addReg(AArch64::D0 + 2 * I) .addReg(AArch64::SP) - .addImm(-12 - I), + .addImm(-2), *STI); - OutStreamer->emitInstruction(MCInstBuilder(AArch64::SUBXri) - .addReg(AArch64::SP) - .addReg(AArch64::SP) - .addImm(144) - .addImm(0), - *STI); - OutStreamer->emitInstruction( MCInstBuilder(AArch64::BL) .addOperand(MCOperand::createExpr(lowerConstant(GI.getResolver()))), @@ -2081,34 +2030,30 @@ void AArch64AsmPrinter::emitManualSymbolResolver(Module &M, .addImm(0), *STI); - OutStreamer->emitInstruction(MCInstBuilder(AArch64::ADDXri) - .addReg(AArch64::SP) - .addReg(AArch64::SP) - .addImm(144) - .addImm(0), - *STI); - - for (int I = 6; I != -2; I -= 2) - OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDPDi) - .addReg(AArch64::D1 + I) - .addReg(AArch64::D0 + I) + for (int I = 3; I != -1; --I) + OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDPDpost) + .addReg(AArch64::SP) + .addReg(AArch64::D1 + 2 * I) + .addReg(AArch64::D0 + 2 * I) .addReg(AArch64::SP) - .addImm(-12 - I), + .addImm(2), *STI); - for (int I = 6; I != -2; I -= 2) - OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDPXi) - .addReg(AArch64::X1 + I) - .addReg(AArch64::X0 + I) + for (int I = 3; I != -1; --I) + OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDPXpost) .addReg(AArch64::SP) - .addImm(-4 - I), + .addReg(AArch64::X1 + 2 * I) + .addReg(AArch64::X0 + 2 * I) + .addReg(AArch64::SP) + .addImm(2), *STI); - OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDPXi) + OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDPXpost) + .addReg(AArch64::SP) .addReg(AArch64::FP) .addReg(AArch64::LR) .addReg(AArch64::SP) - .addImm(-2), + .addImm(2), *STI); OutStreamer->emitInstruction(MCInstBuilder(TM.getTargetTriple().isArm64e() @@ -2118,27 +2063,6 @@ void AArch64AsmPrinter::emitManualSymbolResolver(Module &M, *STI); } -void AArch64AsmPrinter::emitGlobalIFunc(Module &M, const GlobalIFunc &GI) { - if (!TM.getTargetTriple().isOSBinFormatMachO()) - return AsmPrinter::emitGlobalIFunc(M, GI); - - switch (PreferredIFuncLowering) { - case IFuncLowering::SymbolResolverAlways: - return emitLinkerSymbolResolver(M, GI); - case IFuncLowering::SymbolResolverNever: - return emitManualSymbolResolver(M, GI); - case IFuncLowering::SymbolResolverIfSupported: - if (GI.hasExternalLinkage() || !MAI->getWeakRefDirective()) - return emitLinkerSymbolResolver(M, GI); - else if (GI.hasWeakLinkage() || GI.hasLinkOnceLinkage()) - // NOTE: non-global .symbol_resolvers are not yet supported by Darwin - // linkers - return emitManualSymbolResolver(M, GI); - else - assert(GI.hasLocalLinkage() && "Invalid ifunc linkage"); - } -} - // Force static initialization. extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeAArch64AsmPrinter() { RegisterAsmPrinter X(getTheAArch64leTarget()); diff --git a/llvm/test/CodeGen/AArch64/ifunc-asm.ll b/llvm/test/CodeGen/AArch64/ifunc-asm.ll index 7eff692da83ff..18c57b577333e 100644 --- a/llvm/test/CodeGen/AArch64/ifunc-asm.ll +++ b/llvm/test/CodeGen/AArch64/ifunc-asm.ll @@ -1,86 +1,72 @@ ; RUN: llc -mtriple=arm64-unknown-linux-gnu %s -filetype=asm -o - | FileCheck %s --check-prefixes=ELF -; RUN: llc -mtriple=arm64-apple-darwin %s -filetype=asm -o - -arm64-darwin-ifunc-symbol_resolver=always | FileCheck %s --check-prefixes=MACHO,MACHO-LINKER -; RUN: llc -mtriple=arm64-apple-darwin %s -filetype=asm -o - -arm64-darwin-ifunc-symbol_resolver=if_supported | FileCheck %s --check-prefixes=MACHO,MACHO-DEFAULT -; RUN: llc -mtriple=arm64-apple-darwin %s -filetype=asm -o - -arm64-darwin-ifunc-symbol_resolver=never | FileCheck %s --check-prefixes=MACHO,MACHO-MANUAL -; RUN: llc -mtriple=arm64-apple-darwin %s -filetype=asm -o - | FileCheck %s --check-prefixes=MACHO,MACHO-MANUAL -; RUN: llc -mtriple=arm64-apple-darwin %s -filetype=asm -o - -global-isel | FileCheck %s --check-prefixes=MACHO,MACHO-MANUAL +; RUN: llc -mtriple=arm64-apple-darwin %s -filetype=asm -o - | FileCheck %s --check-prefix=MACHO +; RUN: llc -mtriple=arm64-apple-darwin %s -filetype=asm -o - -global-isel | FileCheck %s --check-prefix=MACHO define internal ptr @the_resolver() { entry: ret ptr null } -; ELF: .type the_resolver,@function -; ELF-NEXT: the_resolver: +; ELF: .type the_resolver,@function +; ELF-NEXT: the_resolver: -; MACHO: .p2align 2 -; MACHO-NEXT: _the_resolver +; MACHO: .p2align 2 +; MACHO-NEXT: _the_resolver: @global_ifunc = ifunc i32 (i32), ptr @the_resolver -; ELF: .globl global_ifunc -; ELF-NEXT: .type global_ifunc,@gnu_indirect_function -; ELF-NEXT: .set global_ifunc, the_resolver +; ELF: .globl global_ifunc +; ELF-NEXT: .type global_ifunc,@gnu_indirect_function +; ELF-NEXT: .set global_ifunc, the_resolver -; MACHO-LINKER: .globl _global_ifunc -; MACHO-LINKER-NEXT: .p2align 2 -; MACHO-LINKER-NEXT: _global_ifunc: -; MACHO-LINKER-NEXT: .symbol_resolver _global_ifunc -; MACHO-LINKER-NEXT: b _the_resolver +; MACHO: .section __DATA,__data +; MACHO-NEXT: .globl _global_ifunc.lazy_pointer +; MACHO-NEXT: .p2align 3, 0x0 +; MACHO-NEXT: _global_ifunc.lazy_pointer: +; MACHO-NEXT: .quad _global_ifunc.stub_helper -; MACHO-DEFAULT: .globl _global_ifunc -; MACHO-DEFAULT-NEXT: .p2align 2 -; MACHO-DEFAULT-NEXT: _global_ifunc: -; MACHO-DEFAULT-NEXT: .symbol_resolver _global_ifunc -; MACHO-DEFAULT-NEXT: b _the_resolver - -; MACHO-MANUAL: .section __DATA,__data -; MACHO-MANUAL-NEXT: .globl _global_ifunc.lazy_pointer -; MACHO-MANUAL-NEXT: .p2align 3, 0x0 -; MACHO-MANUAL-NEXT: _global_ifunc.lazy_pointer: -; MACHO-MANUAL-NEXT: .quad _global_ifunc.stub_helper - -; MACHO-MANUAL: .section __TEXT,__text,regular,pure_instructions -; MACHO-MANUAL-NEXT: .globl _global_ifunc -; MACHO-MANUAL-NEXT: .p2align 2 -; MACHO-MANUAL-NEXT: _global_ifunc: -; MACHO-MANUAL-NEXT: adrp x16, _global_ifunc.lazy_pointer@GOTPAGE -; MACHO-MANUAL-NEXT: ldr x16, [x16, _global_ifunc.lazy_pointer@GOTPAGEOFF] -; MACHO-MANUAL-NEXT: ldr x16, [x16] -; MACHO-MANUAL-NEXT: br x16 -; MACHO-MANUAL-NEXT: .globl _global_ifunc.stub_helper -; MACHO-MANUAL-NEXT: .p2align 2 -; MACHO-MANUAL-NEXT: _global_ifunc.stub_helper: -; MACHO-MANUAL-NEXT: stp x29, x30, [sp, #-16] -; MACHO-MANUAL-NEXT: sub x29, sp, #16 -; MACHO-MANUAL-NEXT: stp x1, x0, [sp, #-32] -; MACHO-MANUAL-NEXT: stp x3, x2, [sp, #-48] -; MACHO-MANUAL-NEXT: stp x5, x4, [sp, #-64] -; MACHO-MANUAL-NEXT: stp x7, x6, [sp, #-80] -; MACHO-MANUAL-NEXT: stp d1, d0, [sp, #-96] -; MACHO-MANUAL-NEXT: stp d3, d2, [sp, #-112] -; MACHO-MANUAL-NEXT: stp d5, d4, [sp, #-128] -; MACHO-MANUAL-NEXT: stp d7, d6, [sp, #-144] -; MACHO-MANUAL-NEXT: sub sp, sp, #144 -; MACHO-MANUAL-NEXT: bl _the_resolver -; MACHO-MANUAL-NEXT: adrp x16, _global_ifunc.lazy_pointer@GOTPAGE -; MACHO-MANUAL-NEXT: ldr x16, [x16, _global_ifunc.lazy_pointer@GOTPAGEOFF] -; MACHO-MANUAL-NEXT: str x0, [x16] -; MACHO-MANUAL-NEXT: add x16, x0, #0 -; MACHO-MANUAL-NEXT: add sp, sp, #144 -; MACHO-MANUAL-NEXT: ldp d7, d6, [sp, #-144] -; MACHO-MANUAL-NEXT: ldp d5, d4, [sp, #-128] -; MACHO-MANUAL-NEXT: ldp d3, d2, [sp, #-112] -; MACHO-MANUAL-NEXT: ldp d1, d0, [sp, #-96] -; MACHO-MANUAL-NEXT: ldp x7, x6, [sp, #-80] -; MACHO-MANUAL-NEXT: ldp x5, x4, [sp, #-64] -; MACHO-MANUAL-NEXT: ldp x3, x2, [sp, #-48] -; MACHO-MANUAL-NEXT: ldp x1, x0, [sp, #-32] -; MACHO-MANUAL-NEXT: ldp x29, x30, [sp, #-16] -; MACHO-MANUAL-NEXT: br x16 +; MACHO: .section __TEXT,__text,regular,pure_instructions +; MACHO-NEXT: .globl _global_ifunc +; MACHO-NEXT: .p2align 2 +; MACHO-NEXT: _global_ifunc: +; MACHO-NEXT: adrp x16, _global_ifunc.lazy_pointer@GOTPAGE +; MACHO-NEXT: ldr x16, [x16, _global_ifunc.lazy_pointer@GOTPAGEOFF] +; MACHO-NEXT: ldr x16, [x16] +; MACHO-NEXT: br x16 +; MACHO-NEXT: .globl _global_ifunc.stub_helper +; MACHO-NEXT: .p2align 2 +; MACHO-NEXT: _global_ifunc.stub_helper: +; MACHO-NEXT: stp x29, x30, [sp, #-16]! +; MACHO-NEXT: mov x29, sp +; MACHO-NEXT: stp x1, x0, [sp, #-16]! +; MACHO-NEXT: stp x3, x2, [sp, #-16]! +; MACHO-NEXT: stp x5, x4, [sp, #-16]! +; MACHO-NEXT: stp x7, x6, [sp, #-16]! +; MACHO-NEXT: stp d1, d0, [sp, #-16]! +; MACHO-NEXT: stp d3, d2, [sp, #-16]! +; MACHO-NEXT: stp d5, d4, [sp, #-16]! +; MACHO-NEXT: stp d7, d6, [sp, #-16]! +; MACHO-NEXT: bl _the_resolver +; MACHO-NEXT: adrp x16, _global_ifunc.lazy_pointer@GOTPAGE +; MACHO-NEXT: ldr x16, [x16, _global_ifunc.lazy_pointer@GOTPAGEOFF] +; MACHO-NEXT: str x0, [x16] +; MACHO-NEXT: add x16, x0, #0 +; MACHO-NEXT: ldp d7, d6, [sp], #16 +; MACHO-NEXT: ldp d5, d4, [sp], #16 +; MACHO-NEXT: ldp d3, d2, [sp], #16 +; MACHO-NEXT: ldp d1, d0, [sp], #16 +; MACHO-NEXT: ldp x7, x6, [sp], #16 +; MACHO-NEXT: ldp x5, x4, [sp], #16 +; MACHO-NEXT: ldp x3, x2, [sp], #16 +; MACHO-NEXT: ldp x1, x0, [sp], #16 +; MACHO-NEXT: ldp x29, x30, [sp], #16 +; MACHO-NEXT: br x16 @weak_ifunc = weak ifunc i32 (i32), ptr @the_resolver ; ELF: .type weak_ifunc,@gnu_indirect_function -; MACHO-LINKER: .symbol_resolver _weak_ifunc -; MACHO-MANUAL: _weak_ifunc.stub_helper: -; MACHO-DEFEAULT: _weak_ifunc.stub_helper: \ No newline at end of file +; MACHO: .weak_reference _weak_ifunc.lazy_pointer +; MACHO: _weak_ifunc.lazy_pointer: +; MACHO: .weak_reference _weak_ifunc +; MACHO: _weak_ifunc: +; MACHO: .weak_reference _weak_ifunc.stub_helper +; MACHO: _weak_ifunc.stub_helper: \ No newline at end of file From 672624d8d2daadcf402603df0fce2eb3b7cf18ec Mon Sep 17 00:00:00 2001 From: Jon Roelofs Date: Fri, 1 Dec 2023 13:33:02 -0800 Subject: [PATCH 11/13] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20?= =?UTF-8?q?changes=20introduced=20through=20rebase?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Created using spr 1.3.4 [skip ci] --- llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp index f19dcb5be1722..3aca166786128 100644 --- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp +++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp @@ -1821,9 +1821,9 @@ void AArch64AsmPrinter::emitGlobalIFunc(Module &M, const GlobalIFunc &GI) { // On Darwin platforms, emit a manually-constructed .symbol_resolver that // implements the symbol resolution duties of the IFunc. // - // Normally, this would be handled by linker magic, but unfortunately there are - // a few limitations in ld64 and ld-prime's implementation of .symbol_resolver - // that mean we can't always use them: + // Normally, this would be handled by linker magic, but unfortunately there + // are a few limitations in ld64 and ld-prime's implementation of + // .symbol_resolver that mean we can't always use them: // // * resolvers cannot be the target of an alias // * resolvers cannot have private linkage From 9995a6b8cbc10d4ec56ed5432e9b45bdef83ecc9 Mon Sep 17 00:00:00 2001 From: Jon Roelofs Date: Fri, 8 Dec 2023 13:13:23 -0800 Subject: [PATCH 12/13] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20?= =?UTF-8?q?changes=20introduced=20through=20rebase?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Created using spr 1.3.4 [skip ci] --- llvm/lib/CodeGen/GlobalISel/CallLowering.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp b/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp index d21fa1bf1c64c..58e09841e3dd4 100644 --- a/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp +++ b/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp @@ -144,14 +144,15 @@ bool CallLowering::lowerCall(MachineIRBuilder &MIRBuilder, const CallBase &CB, // Try looking through a bitcast from one function type to another. // Commonly happens with calls to objc_msgSend(). const Value *CalleeV = CB.getCalledOperand()->stripPointerCasts(); - if (isa(CalleeV) && + if (const Function *F = dyn_cast(CalleeV)) + Info.Callee = MachineOperand::CreateGA(F, 0); + else if (isa(CalleeV) && MF.getTarget().getTargetTriple().isOSBinFormatMachO()) { - // ld64 requires that .symbol_resolvers to be called via a stub, so these - // must always be a direct call. + // IR IFuncs can't be forward declared (only defined), so the callee must be + // in the same TU and therefore we can direct-call it without worrying about + // it being out of range. Info.Callee = MachineOperand::CreateGA(cast(CalleeV), 0); - } else if (const Function *F = dyn_cast(CalleeV)) - Info.Callee = MachineOperand::CreateGA(F, 0); - else + } else Info.Callee = MachineOperand::CreateReg(GetCalleeReg(), false); Register ReturnHintAlignReg; From d244734f0a9d18098c619c136c8c0f1f522943b6 Mon Sep 17 00:00:00 2001 From: Jon Roelofs Date: Fri, 8 Dec 2023 14:11:37 -0800 Subject: [PATCH 13/13] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20?= =?UTF-8?q?changes=20introduced=20through=20rebase?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Created using spr 1.3.4 [skip ci] --- llvm/lib/CodeGen/GlobalISel/CallLowering.cpp | 3 +-- .../AArch64/GlobalISel/call-lowering-ifunc.ll | 27 +++++++------------ 2 files changed, 10 insertions(+), 20 deletions(-) diff --git a/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp b/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp index e7030a2639eb0..a6fb9ab49c439 100644 --- a/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp +++ b/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp @@ -146,8 +146,7 @@ bool CallLowering::lowerCall(MachineIRBuilder &MIRBuilder, const CallBase &CB, const Value *CalleeV = CB.getCalledOperand()->stripPointerCasts(); if (const Function *F = dyn_cast(CalleeV)) Info.Callee = MachineOperand::CreateGA(F, 0); - else if (isa(CalleeV) && - MF.getTarget().getTargetTriple().isOSBinFormatMachO()) { + else if (isa(CalleeV)) { // IR IFuncs can't be forward declared (only defined), so the callee must be // in the same TU and therefore we can direct-call it without worrying about // it being out of range. diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/call-lowering-ifunc.ll b/llvm/test/CodeGen/AArch64/GlobalISel/call-lowering-ifunc.ll index 8e51845c2faa9..982f096fdba55 100644 --- a/llvm/test/CodeGen/AArch64/GlobalISel/call-lowering-ifunc.ll +++ b/llvm/test/CodeGen/AArch64/GlobalISel/call-lowering-ifunc.ll @@ -1,6 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py -; RUN: llc -mtriple=aarch64-macho -global-isel -stop-after=irtranslator -verify-machineinstrs -o - %s | FileCheck %s --check-prefixes=MACHO,CHECK -; RUN: llc -mtriple=aarch64-elf -global-isel -stop-after=irtranslator -verify-machineinstrs -o - %s | FileCheck %s --check-prefixes=ELF,CHECK +; RUN: llc -mtriple=aarch64-macho -global-isel -stop-after=irtranslator -verify-machineinstrs -o - %s | FileCheck %s +; RUN: llc -mtriple=aarch64-elf -global-isel -stop-after=irtranslator -verify-machineinstrs -o - %s | FileCheck %s @foo_ifunc = ifunc i32 (i32), ptr @foo_resolver @@ -15,22 +15,13 @@ entry: } define void @caller() { - ; MACHO-LABEL: name: caller - ; MACHO: bb.1.entry: - ; MACHO-NEXT: ADJCALLSTACKDOWN 0, 0, implicit-def $sp, implicit $sp - ; MACHO-NEXT: BL @foo_ifunc, csr_aarch64_aapcs, implicit-def $lr, implicit $sp, implicit-def $w0 - ; MACHO-NEXT: ADJCALLSTACKUP 0, 0, implicit-def $sp, implicit $sp - ; MACHO-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $w0 - ; MACHO-NEXT: RET_ReallyLR - ; - ; ELF-LABEL: name: caller - ; ELF: bb.1.entry: - ; ELF-NEXT: [[GV:%[0-9]+]]:gpr64(p0) = G_GLOBAL_VALUE @foo_ifunc - ; ELF-NEXT: ADJCALLSTACKDOWN 0, 0, implicit-def $sp, implicit $sp - ; ELF-NEXT: BLR [[GV]](p0), csr_aarch64_aapcs, implicit-def $lr, implicit $sp, implicit-def $w0 - ; ELF-NEXT: ADJCALLSTACKUP 0, 0, implicit-def $sp, implicit $sp - ; ELF-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $w0 - ; ELF-NEXT: RET_ReallyLR + ; CHECK-LABEL: name: caller + ; CHECK: bb.1.entry: + ; CHECK-NEXT: ADJCALLSTACKDOWN 0, 0, implicit-def $sp, implicit $sp + ; CHECK-NEXT: BL @foo_ifunc, csr_aarch64_aapcs, implicit-def $lr, implicit $sp, implicit-def $w0 + ; CHECK-NEXT: ADJCALLSTACKUP 0, 0, implicit-def $sp, implicit $sp + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $w0 + ; CHECK-NEXT: RET_ReallyLR entry: %0 = call i32 @foo_ifunc() ret void