Skip to content

Commit 26e8e06

Browse files
authored
Merge pull request #60 from sjavora/triple-subarch
[Triple] Add SubArchs, add validation for thumb architectures
2 parents f4f4759 + cf08eb9 commit 26e8e06

File tree

2 files changed

+296
-22
lines changed

2 files changed

+296
-22
lines changed

Sources/SwiftDriver/Utilities/Triple.swift

Lines changed: 254 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -606,10 +606,11 @@ extension Triple {
606606
// Parse ARM architectures not handled by `parse`. On its own, this is not
607607
// enough to correctly parse an ARM architecture.
608608
private static func parseARMArch<S: StringProtocol>(_ archName: S) -> Triple.Arch? {
609+
609610
let ISA = ARMISA(archName: archName)
610611
let endianness = Endianness(armArchName: archName)
611612

612-
var arch: Triple.Arch? = nil
613+
let arch: Triple.Arch?
613614
switch (endianness, ISA) {
614615
case (.little, .arm):
615616
arch = .arm
@@ -623,15 +624,94 @@ extension Triple {
623624
arch = .thumbeb
624625
case (.big, .aarch64):
625626
arch = .aarch64_be
626-
default:
627-
break
627+
case (nil, _), (_, nil):
628+
arch = nil
629+
}
630+
631+
let cannonicalArchName = cannonicalARMArchName(from: archName)
632+
633+
if cannonicalArchName.isEmpty {
634+
return nil
635+
}
636+
637+
// Thumb only exists in v4+
638+
if ISA == .thumb && (cannonicalArchName.hasPrefix("v2") || cannonicalArchName.hasPrefix("v3")) {
639+
return nil
628640
}
629641

630-
// FIXME: thumb architectures require additional validation. See LLVM's [parseARMArch](https://llvm.org/doxygen/Triple_8cpp.html#a721eb5bffb57cea96d7a9b45cbe302cf)
642+
// Thumb only for v6m
643+
if case .arm(let subArch) = Triple.SubArch.parse(archName), subArch.profile == .m && subArch.version == 6 {
644+
if endianness == .big {
645+
return .thumbeb
646+
} else {
647+
return .thumb
648+
}
649+
}
631650

632651
return arch
633652
}
634653

654+
// Based on LLVM's ARM::getCanonicalArchName
655+
//
656+
// MArch is expected to be of the form (arm|thumb)?(eb)?(v.+)?(eb)?, but
657+
// (iwmmxt|xscale)(eb)? is also permitted. If the former, return
658+
// "v.+", if the latter, return unmodified string, minus 'eb'.
659+
// If invalid, return empty string.
660+
fileprivate static func cannonicalARMArchName<S: StringProtocol>(from arch: S) -> String {
661+
var name = Substring(arch)
662+
663+
func dropPrefix(_ prefix: String) {
664+
if name.hasPrefix(prefix) {
665+
name = name.dropFirst(prefix.count)
666+
}
667+
}
668+
669+
let possiblePrefixes = ["arm64_32", "arm64", "aarch64_32", "arm", "thumb", "aarch64"]
670+
671+
if let prefix = possiblePrefixes.first(where: name.hasPrefix) {
672+
dropPrefix(prefix)
673+
674+
if prefix == "aarch64" {
675+
// AArch64 uses "_be", not "eb" suffix.
676+
if name.contains("eb") {
677+
return ""
678+
}
679+
680+
dropPrefix("_be")
681+
}
682+
}
683+
684+
// Ex. "armebv7", move past the "eb".
685+
if name != arch {
686+
dropPrefix("eb")
687+
}
688+
// Or, if it ends with eb ("armv7eb"), chop it off.
689+
else if name.hasSuffix("eb") {
690+
name = name.dropLast(2)
691+
}
692+
693+
// Reached the end - arch is valid.
694+
if name.isEmpty {
695+
return String(arch)
696+
}
697+
698+
// Only match non-marketing names
699+
if name != arch {
700+
// Must start with 'vN'.
701+
if name.count >= 2 && (name.first != "v" || !name.dropFirst().first!.isNumber) {
702+
return ""
703+
}
704+
705+
// Can't have an extra 'eb'.
706+
if name.hasPrefix("eb") {
707+
return ""
708+
}
709+
}
710+
711+
// Arch will either be a 'v' name (v7a) or a marketing name (xscale).
712+
return String(name)
713+
}
714+
635715
private static func parseBPFArch<S: StringProtocol>(_ archName: S) -> Triple.Arch? {
636716

637717
let isLittleEndianHost = 1.littleEndian == 1
@@ -682,8 +762,176 @@ extension Triple {
682762

683763
extension Triple {
684764
public enum SubArch: Hashable {
685-
fileprivate static func parse(_ component: Substring) -> Triple.SubArch? {
686-
return nil
765+
766+
public enum ARM {
767+
768+
public enum Profile {
769+
case a, r, m
770+
}
771+
772+
case v2
773+
case v2a
774+
case v3
775+
case v3m
776+
case v4
777+
case v4t
778+
case v5
779+
case v5e
780+
case v6
781+
case v6k
782+
case v6kz
783+
case v6m
784+
case v6t2
785+
case v7
786+
case v7em
787+
case v7k
788+
case v7m
789+
case v7r
790+
case v7s
791+
case v7ve
792+
case v8
793+
case v8_1a
794+
case v8_1m_mainline
795+
case v8_2a
796+
case v8_3a
797+
case v8_4a
798+
case v8_5a
799+
case v8m_baseline
800+
case v8m_mainline
801+
case v8r
802+
803+
var profile: Triple.SubArch.ARM.Profile? {
804+
switch self {
805+
case .v6m, .v7m, .v7em, .v8m_mainline, .v8m_baseline, .v8_1m_mainline:
806+
return .m
807+
case .v7r, .v8r:
808+
return .r
809+
case .v7, .v7ve, .v7k, .v8, .v8_1a, .v8_2a, .v8_3a, .v8_4a, .v8_5a:
810+
return .a
811+
case .v2, .v2a, .v3, .v3m, .v4, .v4t, .v5, .v5e, .v6, .v6k, .v6kz, .v6t2, .v7s:
812+
return nil
813+
}
814+
}
815+
816+
var version: Int {
817+
switch self {
818+
case .v2, .v2a:
819+
return 2
820+
case .v3, .v3m:
821+
return 3
822+
case .v4, .v4t:
823+
return 4
824+
case .v5, .v5e:
825+
return 5
826+
case .v6, .v6k, .v6kz, .v6m, .v6t2:
827+
return 6
828+
case .v7, .v7em, .v7k, .v7m, .v7r, .v7s, .v7ve:
829+
return 7
830+
case .v8, .v8_1a, .v8_1m_mainline, .v8_2a, .v8_3a, .v8_4a, .v8_5a, .v8m_baseline, .v8m_mainline, .v8r:
831+
return 8
832+
}
833+
}
834+
}
835+
836+
public enum Kalimba {
837+
case v3
838+
case v4
839+
case v5
840+
}
841+
842+
public enum MIPS {
843+
case r6
844+
}
845+
846+
case arm(ARM)
847+
case kalimba(Kalimba)
848+
case mips(MIPS)
849+
850+
fileprivate static func parse<S: StringProtocol>(_ component: S) -> Triple.SubArch? {
851+
852+
if component.hasPrefix("mips") && (component.hasSuffix("r6el") || component.hasSuffix("r6")) {
853+
return .mips(.r6)
854+
}
855+
856+
let armSubArch = Triple.Arch.cannonicalARMArchName(from: component)
857+
858+
if armSubArch.isEmpty {
859+
switch component {
860+
case _ where component.hasSuffix("kalimba3"):
861+
return .kalimba(.v3)
862+
case _ where component.hasSuffix("kalimba4"):
863+
return .kalimba(.v4)
864+
case _ where component.hasSuffix("kalimba5"):
865+
return .kalimba(.v5)
866+
default:
867+
return nil
868+
}
869+
}
870+
871+
switch armSubArch {
872+
case "v2":
873+
return .arm(.v2)
874+
case "v2a":
875+
return .arm(.v2a)
876+
case "v3":
877+
return .arm(.v3)
878+
case "v3m":
879+
return .arm(.v3m)
880+
case "v4":
881+
return .arm(.v4)
882+
case "v4t":
883+
return .arm(.v4t)
884+
case "v5t":
885+
return .arm(.v5)
886+
case "v5te", "v5tej", "xscale":
887+
return .arm(.v5e)
888+
case "v6":
889+
return .arm(.v6)
890+
case "v6k":
891+
return .arm(.v6k)
892+
case "v6kz":
893+
return .arm(.v6kz)
894+
case "v6-m":
895+
return .arm(.v6m)
896+
case "v6t2":
897+
return .arm(.v6t2)
898+
case "v7-a":
899+
return .arm(.v7)
900+
case "v7k":
901+
return .arm(.v7k)
902+
case "v7-m":
903+
return .arm(.v7m)
904+
case "v7e-m":
905+
return .arm(.v7em)
906+
case "v7-r":
907+
return .arm(.v7r)
908+
case "v7s":
909+
return .arm(.v7s)
910+
case "v7ve":
911+
return .arm(.v7ve)
912+
case "v8-a":
913+
return .arm(.v8)
914+
case "v8-m.main":
915+
return .arm(.v8m_mainline)
916+
case "v8-m.base":
917+
return .arm(.v8m_baseline)
918+
case "v8-r":
919+
return .arm(.v8r)
920+
case "v8.1-m.main":
921+
return .arm(.v8_1m_mainline)
922+
case "v8.1-a":
923+
return .arm(.v8_1a)
924+
case "v8.2-a":
925+
return .arm(.v8_2a)
926+
case "v8.3-a":
927+
return .arm(.v8_3a)
928+
case "v8.4-a":
929+
return .arm(.v8_4a)
930+
case "v8.5-a":
931+
return .arm(.v8_5a)
932+
default:
933+
return nil
934+
}
687935
}
688936
}
689937
}

0 commit comments

Comments
 (0)