diff --git a/llvm/include/llvm/IR/Module.h b/llvm/include/llvm/IR/Module.h index bd3a196c718194..4ddbd6ff14b3c1 100644 --- a/llvm/include/llvm/IR/Module.h +++ b/llvm/include/llvm/IR/Module.h @@ -934,6 +934,17 @@ class LLVM_EXTERNAL_VISIBILITY Module { /// Set the partial sample profile ratio in the profile summary module flag, /// if applicable. void setPartialSampleProfileRatio(const ModuleSummaryIndex &Index); + + /// Get the target variant triple which is a string describing a variant of + /// the target host platform. For example, Mac Catalyst can be a variant + /// target triple for a macOS target. + /// @returns a string containing the target variant triple. + StringRef getDarwinTargetVariantTriple() const; + + /// Get the target variant version build SDK version metadata. + /// + /// An empty version is returned if no such metadata is attached. + VersionTuple getDarwinTargetVariantSDKVersion() const; }; /// Given "llvm.used" or "llvm.compiler.used" as a global name, collect the diff --git a/llvm/include/llvm/MC/MCAssembler.h b/llvm/include/llvm/MC/MCAssembler.h index 1f670e3973ce27..9d5cb620c9de4f 100644 --- a/llvm/include/llvm/MC/MCAssembler.h +++ b/llvm/include/llvm/MC/MCAssembler.h @@ -153,6 +153,7 @@ class MCAssembler { MCLOHContainer LOHContainer; VersionInfoType VersionInfo; + VersionInfoType DarwinTargetVariantVersionInfo; /// Evaluate a fixup to a relocatable expression and the value which should be /// placed into the fixup. @@ -285,6 +286,21 @@ class MCAssembler { VersionInfo.SDKVersion = SDKVersion; } + const VersionInfoType &getDarwinTargetVariantVersionInfo() const { + return DarwinTargetVariantVersionInfo; + } + void setDarwinTargetVariantBuildVersion(MachO::PlatformType Platform, + unsigned Major, unsigned Minor, + unsigned Update, + VersionTuple SDKVersion) { + DarwinTargetVariantVersionInfo.EmitBuildVersion = true; + DarwinTargetVariantVersionInfo.TypeOrPlatform.Platform = Platform; + DarwinTargetVariantVersionInfo.Major = Major; + DarwinTargetVariantVersionInfo.Minor = Minor; + DarwinTargetVariantVersionInfo.Update = Update; + DarwinTargetVariantVersionInfo.SDKVersion = SDKVersion; + } + /// Reuse an assembler instance /// void reset(); diff --git a/llvm/include/llvm/MC/MCObjectFileInfo.h b/llvm/include/llvm/MC/MCObjectFileInfo.h index ba7450ac64f130..5e0cccaba77fad 100644 --- a/llvm/include/llvm/MC/MCObjectFileInfo.h +++ b/llvm/include/llvm/MC/MCObjectFileInfo.h @@ -427,6 +427,8 @@ class MCObjectFileInfo { bool PositionIndependent = false; MCContext *Ctx = nullptr; VersionTuple SDKVersion; + Optional DarwinTargetVariantTriple; + VersionTuple DarwinTargetVariantSDKVersion; void initMachOMCObjectFileInfo(const Triple &T); void initELFMCObjectFileInfo(const Triple &T, bool Large); @@ -442,6 +444,23 @@ class MCObjectFileInfo { } const VersionTuple &getSDKVersion() const { return SDKVersion; } + + void setDarwinTargetVariantTriple(const Triple &T) { + DarwinTargetVariantTriple = T; + } + + const Triple *getDarwinTargetVariantTriple() const { + return DarwinTargetVariantTriple ? DarwinTargetVariantTriple.getPointer() + : nullptr; + } + + void setDarwinTargetVariantSDKVersion(const VersionTuple &TheSDKVersion) { + DarwinTargetVariantSDKVersion = TheSDKVersion; + } + + const VersionTuple &getDarwinTargetVariantSDKVersion() const { + return DarwinTargetVariantSDKVersion; + } }; } // end namespace llvm diff --git a/llvm/include/llvm/MC/MCStreamer.h b/llvm/include/llvm/MC/MCStreamer.h index e00f50f617fa25..428e4039e77f0b 100644 --- a/llvm/include/llvm/MC/MCStreamer.h +++ b/llvm/include/llvm/MC/MCStreamer.h @@ -496,8 +496,16 @@ class MCStreamer { unsigned Minor, unsigned Update, VersionTuple SDKVersion) {} + virtual void emitDarwinTargetVariantBuildVersion(unsigned Platform, + unsigned Major, + unsigned Minor, + unsigned Update, + VersionTuple SDKVersion) {} + void emitVersionForTarget(const Triple &Target, - const VersionTuple &SDKVersion); + const VersionTuple &SDKVersion, + const Triple *DarwinTargetVariantTriple, + const VersionTuple &DarwinTargetVariantSDKVersion); /// Note in the output that the specified \p Func is a Thumb mode /// function (ARM target only). diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index 828cb760b82ea2..183f4516f4c2b9 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -288,7 +288,11 @@ bool AsmPrinter::doInitialization(Module &M) { // use the directive, where it would need the same conditionalization // anyway. const Triple &Target = TM.getTargetTriple(); - OutStreamer->emitVersionForTarget(Target, M.getSDKVersion()); + Triple TVT(M.getDarwinTargetVariantTriple()); + OutStreamer->emitVersionForTarget( + Target, M.getSDKVersion(), + M.getDarwinTargetVariantTriple().empty() ? nullptr : &TVT, + M.getDarwinTargetVariantSDKVersion()); // Allow the target to emit any magic that it wants at the start of the file. emitStartOfAsmFile(M); diff --git a/llvm/lib/IR/Module.cpp b/llvm/lib/IR/Module.cpp index 63ea41fba89ab8..a0485a59d0e08e 100644 --- a/llvm/lib/IR/Module.cpp +++ b/llvm/lib/IR/Module.cpp @@ -750,8 +750,8 @@ void Module::setSDKVersion(const VersionTuple &V) { ConstantDataArray::get(Context, Entries)); } -VersionTuple Module::getSDKVersion() const { - auto *CM = dyn_cast_or_null(getModuleFlag("SDK Version")); +static VersionTuple getSDKVersionMD(Metadata *MD) { + auto *CM = dyn_cast_or_null(MD); if (!CM) return {}; auto *Arr = dyn_cast_or_null(CM->getValue()); @@ -775,6 +775,10 @@ VersionTuple Module::getSDKVersion() const { return Result; } +VersionTuple Module::getSDKVersion() const { + return getSDKVersionMD(getModuleFlag("SDK Version")); +} + GlobalVariable *llvm::collectUsedGlobalVariables( const Module &M, SmallVectorImpl &Vec, bool CompilerUsed) { const char *Name = CompilerUsed ? "llvm.compiler.used" : "llvm.used"; @@ -809,3 +813,13 @@ void Module::setPartialSampleProfileRatio(const ModuleSummaryIndex &Index) { } } } + +StringRef Module::getDarwinTargetVariantTriple() const { + if (const auto *MD = getModuleFlag("darwin.target_variant.triple")) + return cast(MD)->getString(); + return ""; +} + +VersionTuple Module::getDarwinTargetVariantSDKVersion() const { + return getSDKVersionMD(getModuleFlag("darwin.target_variant.SDK Version")); +} diff --git a/llvm/lib/MC/MCAsmStreamer.cpp b/llvm/lib/MC/MCAsmStreamer.cpp index 2ca921017171aa..6cd3bf0d1aabd0 100644 --- a/llvm/lib/MC/MCAsmStreamer.cpp +++ b/llvm/lib/MC/MCAsmStreamer.cpp @@ -168,6 +168,9 @@ class MCAsmStreamer final : public MCStreamer { unsigned Update, VersionTuple SDKVersion) override; void emitBuildVersion(unsigned Platform, unsigned Major, unsigned Minor, unsigned Update, VersionTuple SDKVersion) override; + void emitDarwinTargetVariantBuildVersion(unsigned Platform, unsigned Major, + unsigned Minor, unsigned Update, + VersionTuple SDKVersion) override; void emitThumbFunc(MCSymbol *Func) override; void emitAssignment(MCSymbol *Symbol, const MCExpr *Value) override; @@ -640,6 +643,12 @@ void MCAsmStreamer::emitBuildVersion(unsigned Platform, unsigned Major, EmitEOL(); } +void MCAsmStreamer::emitDarwinTargetVariantBuildVersion( + unsigned Platform, unsigned Major, unsigned Minor, unsigned Update, + VersionTuple SDKVersion) { + emitBuildVersion(Platform, Major, Minor, Update, SDKVersion); +} + void MCAsmStreamer::emitThumbFunc(MCSymbol *Func) { // This needs to emit to a temporary string to get properly quoted // MCSymbols when they have spaces in them. diff --git a/llvm/lib/MC/MCAssembler.cpp b/llvm/lib/MC/MCAssembler.cpp index d5e9f4fc66bcee..a8837bbf57c7a2 100644 --- a/llvm/lib/MC/MCAssembler.cpp +++ b/llvm/lib/MC/MCAssembler.cpp @@ -89,6 +89,7 @@ MCAssembler::MCAssembler(MCContext &Context, BundleAlignSize(0), RelaxAll(false), SubsectionsViaSymbols(false), IncrementalLinkerCompatible(false), ELFHeaderEFlags(0) { VersionInfo.Major = 0; // Major version == 0 for "none specified" + DarwinTargetVariantVersionInfo.Major = 0; } MCAssembler::~MCAssembler() = default; @@ -109,6 +110,8 @@ void MCAssembler::reset() { LOHContainer.reset(); VersionInfo.Major = 0; VersionInfo.SDKVersion = VersionTuple(); + DarwinTargetVariantVersionInfo.Major = 0; + DarwinTargetVariantVersionInfo.SDKVersion = VersionTuple(); // reset objects owned by us if (getBackendPtr()) diff --git a/llvm/lib/MC/MCMachOStreamer.cpp b/llvm/lib/MC/MCMachOStreamer.cpp index aa94b141d8be2f..3edf7a3f49e653 100644 --- a/llvm/lib/MC/MCMachOStreamer.cpp +++ b/llvm/lib/MC/MCMachOStreamer.cpp @@ -92,6 +92,9 @@ class MCMachOStreamer : public MCObjectStreamer { unsigned Update, VersionTuple SDKVersion) override; void emitBuildVersion(unsigned Platform, unsigned Major, unsigned Minor, unsigned Update, VersionTuple SDKVersion) override; + void emitDarwinTargetVariantBuildVersion(unsigned Platform, unsigned Major, + unsigned Minor, unsigned Update, + VersionTuple SDKVersion) override; void emitThumbFunc(MCSymbol *Func) override; bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override; void emitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) override; @@ -283,6 +286,13 @@ void MCMachOStreamer::emitBuildVersion(unsigned Platform, unsigned Major, Update, SDKVersion); } +void MCMachOStreamer::emitDarwinTargetVariantBuildVersion( + unsigned Platform, unsigned Major, unsigned Minor, unsigned Update, + VersionTuple SDKVersion) { + getAssembler().setDarwinTargetVariantBuildVersion( + (MachO::PlatformType)Platform, Major, Minor, Update, SDKVersion); +} + void MCMachOStreamer::emitThumbFunc(MCSymbol *Symbol) { // Remember that the function is a thumb function. Fixup and relocation // values will need adjusted. @@ -516,7 +526,10 @@ MCStreamer *llvm::createMachOStreamer(MCContext &Context, new MCMachOStreamer(Context, std::move(MAB), std::move(OW), std::move(CE), DWARFMustBeAtTheEnd, LabelSections); const Triple &Target = Context.getTargetTriple(); - S->emitVersionForTarget(Target, Context.getObjectFileInfo()->getSDKVersion()); + S->emitVersionForTarget( + Target, Context.getObjectFileInfo()->getSDKVersion(), + Context.getObjectFileInfo()->getDarwinTargetVariantTriple(), + Context.getObjectFileInfo()->getDarwinTargetVariantSDKVersion()); if (RelaxAll) S->getAssembler().setRelaxAll(true); return S; diff --git a/llvm/lib/MC/MCStreamer.cpp b/llvm/lib/MC/MCStreamer.cpp index b0da490327d471..b056311b1b9b53 100644 --- a/llvm/lib/MC/MCStreamer.cpp +++ b/llvm/lib/MC/MCStreamer.cpp @@ -1308,8 +1308,10 @@ getMachoBuildVersionPlatformType(const Triple &Target) { llvm_unreachable("unexpected OS type"); } -void MCStreamer::emitVersionForTarget(const Triple &Target, - const VersionTuple &SDKVersion) { +void MCStreamer::emitVersionForTarget( + const Triple &Target, const VersionTuple &SDKVersion, + const Triple *DarwinTargetVariantTriple, + const VersionTuple &DarwinTargetVariantSDKVersion) { if (!Target.isOSBinFormatMachO() || !Target.isOSDarwin()) return; // Do we even know the version? @@ -1336,13 +1338,45 @@ void MCStreamer::emitVersionForTarget(const Triple &Target, auto LinkedTargetVersion = targetVersionOrMinimumSupportedOSVersion(Target, Version); auto BuildVersionOSVersion = getMachoBuildVersionSupportedOS(Target); + bool ShouldEmitBuildVersion = false; if (BuildVersionOSVersion.empty() || - LinkedTargetVersion >= BuildVersionOSVersion) - return emitBuildVersion(getMachoBuildVersionPlatformType(Target), - LinkedTargetVersion.getMajor(), - LinkedTargetVersion.getMinor().getValueOr(0), - LinkedTargetVersion.getSubminor().getValueOr(0), - SDKVersion); + LinkedTargetVersion >= BuildVersionOSVersion) { + if (Target.isMacCatalystEnvironment() && DarwinTargetVariantTriple && + DarwinTargetVariantTriple->isMacOSX()) { + emitVersionForTarget(*DarwinTargetVariantTriple, + DarwinTargetVariantSDKVersion, + /*TargetVariantTriple=*/nullptr, + /*TargetVariantSDKVersion=*/VersionTuple()); + emitDarwinTargetVariantBuildVersion( + getMachoBuildVersionPlatformType(Target), + LinkedTargetVersion.getMajor(), + LinkedTargetVersion.getMinor().getValueOr(0), + LinkedTargetVersion.getSubminor().getValueOr(0), SDKVersion); + return; + } + emitBuildVersion(getMachoBuildVersionPlatformType(Target), + LinkedTargetVersion.getMajor(), + LinkedTargetVersion.getMinor().getValueOr(0), + LinkedTargetVersion.getSubminor().getValueOr(0), + SDKVersion); + ShouldEmitBuildVersion = true; + } + + if (const Triple *TVT = DarwinTargetVariantTriple) { + if (Target.isMacOSX() && TVT->isMacCatalystEnvironment()) { + auto TVLinkedTargetVersion = + targetVersionOrMinimumSupportedOSVersion(*TVT, TVT->getiOSVersion()); + emitDarwinTargetVariantBuildVersion( + getMachoBuildVersionPlatformType(*TVT), + TVLinkedTargetVersion.getMajor(), + TVLinkedTargetVersion.getMinor().getValueOr(0), + TVLinkedTargetVersion.getSubminor().getValueOr(0), + DarwinTargetVariantSDKVersion); + } + } + + if (ShouldEmitBuildVersion) + return; emitVersionMin(getMachoVersionMinLoadCommandType(Target), LinkedTargetVersion.getMajor(), diff --git a/llvm/lib/MC/MachObjectWriter.cpp b/llvm/lib/MC/MachObjectWriter.cpp index 277d88cf1cd273..3961cf302b1810 100644 --- a/llvm/lib/MC/MachObjectWriter.cpp +++ b/llvm/lib/MC/MachObjectWriter.cpp @@ -779,6 +779,17 @@ uint64_t MachObjectWriter::writeObject(MCAssembler &Asm, LoadCommandsSize += sizeof(MachO::version_min_command); } + const MCAssembler::VersionInfoType &TargetVariantVersionInfo = + Layout.getAssembler().getDarwinTargetVariantVersionInfo(); + + // Add the target variant version info load command size, if used. + if (TargetVariantVersionInfo.Major != 0) { + ++NumLoadCommands; + assert(TargetVariantVersionInfo.EmitBuildVersion && + "target variant should use build version"); + LoadCommandsSize += sizeof(MachO::build_version_command); + } + // Add the data-in-code load command size, if used. unsigned NumDataRegions = Asm.getDataRegions().size(); if (NumDataRegions) { @@ -862,38 +873,43 @@ uint64_t MachObjectWriter::writeObject(MCAssembler &Asm, } // Write out the deployment target information, if it's available. - if (VersionInfo.Major != 0) { - auto EncodeVersion = [](VersionTuple V) -> uint32_t { - assert(!V.empty() && "empty version"); - unsigned Update = V.getSubminor() ? *V.getSubminor() : 0; - unsigned Minor = V.getMinor() ? *V.getMinor() : 0; - assert(Update < 256 && "unencodable update target version"); - assert(Minor < 256 && "unencodable minor target version"); - assert(V.getMajor() < 65536 && "unencodable major target version"); - return Update | (Minor << 8) | (V.getMajor() << 16); - }; - uint32_t EncodedVersion = EncodeVersion( - VersionTuple(VersionInfo.Major, VersionInfo.Minor, VersionInfo.Update)); - uint32_t SDKVersion = !VersionInfo.SDKVersion.empty() - ? EncodeVersion(VersionInfo.SDKVersion) - : 0; - if (VersionInfo.EmitBuildVersion) { - // FIXME: Currently empty tools. Add clang version in the future. - W.write(MachO::LC_BUILD_VERSION); - W.write(sizeof(MachO::build_version_command)); - W.write(VersionInfo.TypeOrPlatform.Platform); - W.write(EncodedVersion); - W.write(SDKVersion); - W.write(0); // Empty tools list. - } else { - MachO::LoadCommandType LCType - = getLCFromMCVM(VersionInfo.TypeOrPlatform.Type); - W.write(LCType); - W.write(sizeof(MachO::version_min_command)); - W.write(EncodedVersion); - W.write(SDKVersion); - } - } + auto EmitDeploymentTargetVersion = + [&](const MCAssembler::VersionInfoType &VersionInfo) { + auto EncodeVersion = [](VersionTuple V) -> uint32_t { + assert(!V.empty() && "empty version"); + unsigned Update = V.getSubminor() ? *V.getSubminor() : 0; + unsigned Minor = V.getMinor() ? *V.getMinor() : 0; + assert(Update < 256 && "unencodable update target version"); + assert(Minor < 256 && "unencodable minor target version"); + assert(V.getMajor() < 65536 && "unencodable major target version"); + return Update | (Minor << 8) | (V.getMajor() << 16); + }; + uint32_t EncodedVersion = EncodeVersion(VersionTuple( + VersionInfo.Major, VersionInfo.Minor, VersionInfo.Update)); + uint32_t SDKVersion = !VersionInfo.SDKVersion.empty() + ? EncodeVersion(VersionInfo.SDKVersion) + : 0; + if (VersionInfo.EmitBuildVersion) { + // FIXME: Currently empty tools. Add clang version in the future. + W.write(MachO::LC_BUILD_VERSION); + W.write(sizeof(MachO::build_version_command)); + W.write(VersionInfo.TypeOrPlatform.Platform); + W.write(EncodedVersion); + W.write(SDKVersion); + W.write(0); // Empty tools list. + } else { + MachO::LoadCommandType LCType = + getLCFromMCVM(VersionInfo.TypeOrPlatform.Type); + W.write(LCType); + W.write(sizeof(MachO::version_min_command)); + W.write(EncodedVersion); + W.write(SDKVersion); + } + }; + if (VersionInfo.Major != 0) + EmitDeploymentTargetVersion(VersionInfo); + if (TargetVariantVersionInfo.Major != 0) + EmitDeploymentTargetVersion(TargetVariantVersionInfo); // Write the data-in-code load command, if used. uint64_t DataInCodeTableEnd = RelocTableEnd + NumDataRegions * 8; diff --git a/llvm/test/MC/MachO/darwin-target-variant-reverse.ll b/llvm/test/MC/MachO/darwin-target-variant-reverse.ll new file mode 100644 index 00000000000000..6d51cd8fffa82b --- /dev/null +++ b/llvm/test/MC/MachO/darwin-target-variant-reverse.ll @@ -0,0 +1,25 @@ +; RUN: llc %s -filetype=obj -o - | llvm-objdump --macho --private-headers - | FileCheck %s + +target triple = "x86_64-apple-ios13.1-macabi"; +!llvm.module.flags = !{!0, !1, !2}; +!0 = !{i32 2, !"SDK Version", [2 x i32] [ i32 13, i32 1 ] }; +!1 = !{i32 1, !"darwin.target_variant.triple", !"x86_64-apple-macos10.15"}; +!2 = !{i32 2, !"darwin.target_variant.SDK Version", [2 x i32] [ i32 10, i32 15 ] }; + +define void @foo() { +entry: + ret void +} + +; CHECK: cmd LC_BUILD_VERSION +; CHECK-NEXT: cmdsize 24 +; CHECK-NEXT: platform macos +; CHECK-NEXT: sdk 10.15 +; CHECK-NEXT: minos 10.15 +; CHECK-NEXT: ntools 0 +; CHECK: cmd LC_BUILD_VERSION +; CHECK-NEXT: cmdsize 24 +; CHECK-NEXT: platform macCatalyst +; CHECK-NEXT: sdk 13.1 +; CHECK-NEXT: minos 13.1 +; CHECK-NEXT: ntools 0 diff --git a/llvm/test/MC/MachO/darwin-target-variant.ll b/llvm/test/MC/MachO/darwin-target-variant.ll new file mode 100644 index 00000000000000..d506ed92c9cc3d --- /dev/null +++ b/llvm/test/MC/MachO/darwin-target-variant.ll @@ -0,0 +1,29 @@ +; RUN: llc %s -filetype=obj -o - | llvm-objdump --macho --private-headers - | FileCheck %s +; RUN: llc %s -filetype=asm -o - | FileCheck --check-prefix=ASM %s + +target triple = "x86_64-apple-macos10.15"; +!llvm.module.flags = !{!0, !1, !2}; +!0 = !{i32 2, !"SDK Version", [3 x i32] [ i32 10, i32 15, i32 1 ] }; +!1 = !{i32 1, !"darwin.target_variant.triple", !"x86_64-apple-ios13.1-macabi"}; +!2 = !{i32 2, !"darwin.target_variant.SDK Version", [2 x i32] [ i32 13, i32 2 ] }; + +define void @foo() { +entry: + ret void +} + +; CHECK: cmd LC_BUILD_VERSION +; CHECK-NEXT: cmdsize 24 +; CHECK-NEXT: platform macos +; CHECK-NEXT: sdk 10.15.1 +; CHECK-NEXT: minos 10.15 +; CHECK-NEXT: ntools 0 +; CHECK: cmd LC_BUILD_VERSION +; CHECK-NEXT: cmdsize 24 +; CHECK-NEXT: platform macCatalyst +; CHECK-NEXT: sdk 13.2 +; CHECK-NEXT: minos 13.1 +; CHECK-NEXT: ntools 0 + +; ASM: .build_version macos, 10, 15 sdk_version 10, 15, 1 +; ASM: .build_version macCatalyst, 13, 1 sdk_version 13, 2