1//===-- llvm/BinaryFormat/MachO.cpp - The MachO file format -----*- C++/-*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "llvm/BinaryFormat/MachO.h"
10#include "llvm/TargetParser/ARMTargetParser.h"
11#include "llvm/TargetParser/Triple.h"
12
13using namespace llvm;
14
15static MachO::CPUSubTypeX86 getX86SubType(const Triple &T) {
16  assert(T.isX86());
17  if (T.isArch32Bit())
18    return MachO::CPU_SUBTYPE_I386_ALL;
19
20  assert(T.isArch64Bit());
21  if (T.getArchName() == "x86_64h")
22    return MachO::CPU_SUBTYPE_X86_64_H;
23  return MachO::CPU_SUBTYPE_X86_64_ALL;
24}
25
26static MachO::CPUSubTypeARM getARMSubType(const Triple &T) {
27  assert(T.isARM() || T.isThumb());
28  StringRef Arch = T.getArchName();
29  ARM::ArchKind AK = ARM::parseArch(Arch);
30  switch (AK) {
31  default:
32    return MachO::CPU_SUBTYPE_ARM_V7;
33  case ARM::ArchKind::ARMV4T:
34    return MachO::CPU_SUBTYPE_ARM_V4T;
35  case ARM::ArchKind::ARMV5T:
36  case ARM::ArchKind::ARMV5TE:
37  case ARM::ArchKind::ARMV5TEJ:
38    return MachO::CPU_SUBTYPE_ARM_V5;
39  case ARM::ArchKind::ARMV6:
40  case ARM::ArchKind::ARMV6K:
41    return MachO::CPU_SUBTYPE_ARM_V6;
42  case ARM::ArchKind::ARMV7A:
43    return MachO::CPU_SUBTYPE_ARM_V7;
44  case ARM::ArchKind::ARMV7S:
45    return MachO::CPU_SUBTYPE_ARM_V7S;
46  case ARM::ArchKind::ARMV7K:
47    return MachO::CPU_SUBTYPE_ARM_V7K;
48  case ARM::ArchKind::ARMV6M:
49    return MachO::CPU_SUBTYPE_ARM_V6M;
50  case ARM::ArchKind::ARMV7M:
51    return MachO::CPU_SUBTYPE_ARM_V7M;
52  case ARM::ArchKind::ARMV7EM:
53    return MachO::CPU_SUBTYPE_ARM_V7EM;
54  }
55}
56
57static MachO::CPUSubTypeARM64 getARM64SubType(const Triple &T) {
58  assert(T.isAArch64());
59  if (T.isArch32Bit())
60    return (MachO::CPUSubTypeARM64)MachO::CPU_SUBTYPE_ARM64_32_V8;
61  if (T.isArm64e())
62    return MachO::CPU_SUBTYPE_ARM64E;
63
64  return MachO::CPU_SUBTYPE_ARM64_ALL;
65}
66
67static MachO::CPUSubTypePowerPC getPowerPCSubType(const Triple &T) {
68  return MachO::CPU_SUBTYPE_POWERPC_ALL;
69}
70
71static Error unsupported(const char *Str, const Triple &T) {
72  return createStringError(std::errc::invalid_argument,
73                           "Unsupported triple for mach-o cpu %s: %s", Str,
74                           T.str().c_str());
75}
76
77Expected<uint32_t> MachO::getCPUType(const Triple &T) {
78  if (!T.isOSBinFormatMachO())
79    return unsupported("type", T);
80  if (T.isX86() && T.isArch32Bit())
81    return MachO::CPU_TYPE_X86;
82  if (T.isX86() && T.isArch64Bit())
83    return MachO::CPU_TYPE_X86_64;
84  if (T.isARM() || T.isThumb())
85    return MachO::CPU_TYPE_ARM;
86  if (T.isAArch64())
87    return T.isArch32Bit() ? MachO::CPU_TYPE_ARM64_32 : MachO::CPU_TYPE_ARM64;
88  if (T.getArch() == Triple::ppc)
89    return MachO::CPU_TYPE_POWERPC;
90  if (T.getArch() == Triple::ppc64)
91    return MachO::CPU_TYPE_POWERPC64;
92  return unsupported("type", T);
93}
94
95Expected<uint32_t> MachO::getCPUSubType(const Triple &T) {
96  if (!T.isOSBinFormatMachO())
97    return unsupported("subtype", T);
98  if (T.isX86())
99    return getX86SubType(T);
100  if (T.isARM() || T.isThumb())
101    return getARMSubType(T);
102  if (T.isAArch64() || T.getArch() == Triple::aarch64_32)
103    return getARM64SubType(T);
104  if (T.getArch() == Triple::ppc || T.getArch() == Triple::ppc64)
105    return getPowerPCSubType(T);
106  return unsupported("subtype", T);
107}
108