1 //===---------------- ARMTargetParserCommon ---------------------*- 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 // Code that is common to ARMTargetParser and AArch64TargetParser. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "llvm/TargetParser/ARMTargetParserCommon.h" 14 #include "llvm/ADT/SmallVector.h" 15 #include "llvm/ADT/StringSwitch.h" 16 17 using namespace llvm; 18 19 StringRef ARM::getArchSynonym(StringRef Arch) { 20 return StringSwitch<StringRef>(Arch) 21 .Case("v5", "v5t") 22 .Case("v5e", "v5te") 23 .Case("v6j", "v6") 24 .Case("v6hl", "v6k") 25 .Cases("v6m", "v6sm", "v6s-m", "v6-m") 26 .Cases("v6z", "v6zk", "v6kz") 27 .Cases("v7", "v7a", "v7hl", "v7l", "v7-a") 28 .Case("v7r", "v7-r") 29 .Case("v7m", "v7-m") 30 .Case("v7em", "v7e-m") 31 .Cases("v8", "v8a", "v8l", "aarch64", "arm64", "v8-a") 32 .Case("v8.1a", "v8.1-a") 33 .Case("v8.2a", "v8.2-a") 34 .Case("v8.3a", "v8.3-a") 35 .Case("v8.4a", "v8.4-a") 36 .Case("v8.5a", "v8.5-a") 37 .Case("v8.6a", "v8.6-a") 38 .Case("v8.7a", "v8.7-a") 39 .Case("v8.8a", "v8.8-a") 40 .Case("v8.9a", "v8.9-a") 41 .Case("v8r", "v8-r") 42 .Cases("v9", "v9a", "v9-a") 43 .Case("v9.1a", "v9.1-a") 44 .Case("v9.2a", "v9.2-a") 45 .Case("v9.3a", "v9.3-a") 46 .Case("v9.4a", "v9.4-a") 47 .Case("v9.5a", "v9.5-a") 48 .Case("v9.6a", "v9.6-a") 49 .Case("v8m.base", "v8-m.base") 50 .Case("v8m.main", "v8-m.main") 51 .Case("v8.1m.main", "v8.1-m.main") 52 .Default(Arch); 53 } 54 55 StringRef ARM::getCanonicalArchName(StringRef Arch) { 56 size_t offset = StringRef::npos; 57 StringRef A = Arch; 58 StringRef Error = ""; 59 60 // Begins with "arm" / "thumb", move past it. 61 if (A.starts_with("arm64_32")) 62 offset = 8; 63 else if (A.starts_with("arm64e")) 64 offset = 6; 65 else if (A.starts_with("arm64")) 66 offset = 5; 67 else if (A.starts_with("aarch64_32")) 68 offset = 10; 69 else if (A.starts_with("arm")) 70 offset = 3; 71 else if (A.starts_with("thumb")) 72 offset = 5; 73 else if (A.starts_with("aarch64")) { 74 offset = 7; 75 // AArch64 uses "_be", not "eb" suffix. 76 if (A.contains("eb")) 77 return Error; 78 if (A.substr(offset, 3) == "_be") 79 offset += 3; 80 } 81 82 // Ex. "armebv7", move past the "eb". 83 if (offset != StringRef::npos && A.substr(offset, 2) == "eb") 84 offset += 2; 85 // Or, if it ends with eb ("armv7eb"), chop it off. 86 else if (A.ends_with("eb")) 87 A = A.substr(0, A.size() - 2); 88 // Trim the head 89 if (offset != StringRef::npos) 90 A = A.substr(offset); 91 92 // Empty string means offset reached the end, which means it's valid. 93 if (A.empty()) 94 return Arch; 95 96 // Only match non-marketing names 97 if (offset != StringRef::npos) { 98 // Must start with 'vN'. 99 if (A.size() >= 2 && (A[0] != 'v' || !std::isdigit(A[1]))) 100 return Error; 101 // Can't have an extra 'eb'. 102 if (A.contains("eb")) 103 return Error; 104 } 105 106 // Arch will either be a 'v' name (v7a) or a marketing name (xscale). 107 return A; 108 } 109 110 ARM::ISAKind ARM::parseArchISA(StringRef Arch) { 111 return StringSwitch<ISAKind>(Arch) 112 .StartsWith("aarch64", ISAKind::AARCH64) 113 .StartsWith("arm64", ISAKind::AARCH64) 114 .StartsWith("thumb", ISAKind::THUMB) 115 .StartsWith("arm", ISAKind::ARM) 116 .Default(ISAKind::INVALID); 117 } 118 119 ARM::EndianKind ARM::parseArchEndian(StringRef Arch) { 120 if (Arch.starts_with("armeb") || Arch.starts_with("thumbeb") || 121 Arch.starts_with("aarch64_be")) 122 return EndianKind::BIG; 123 124 if (Arch.starts_with("arm") || Arch.starts_with("thumb")) { 125 if (Arch.ends_with("eb")) 126 return EndianKind::BIG; 127 else 128 return EndianKind::LITTLE; 129 } 130 131 if (Arch.starts_with("aarch64") || Arch.starts_with("aarch64_32")) 132 return EndianKind::LITTLE; 133 134 return EndianKind::INVALID; 135 } 136 137 // Parse a branch protection specification, which has the form 138 // standard | none | [bti,pac-ret[+b-key,+leaf,+pc]*] 139 // Returns true on success, with individual elements of the specification 140 // returned in `PBP`. Returns false in error, with `Err` containing 141 // an erroneous part of the spec. 142 bool ARM::parseBranchProtection(StringRef Spec, ParsedBranchProtection &PBP, 143 StringRef &Err, bool EnablePAuthLR) { 144 PBP = {"none", "a_key", false, false, false}; 145 if (Spec == "none") 146 return true; // defaults are ok 147 148 if (Spec == "standard") { 149 PBP.Scope = "non-leaf"; 150 PBP.BranchTargetEnforcement = true; 151 PBP.GuardedControlStack = true; 152 PBP.BranchProtectionPAuthLR = EnablePAuthLR; 153 return true; 154 } 155 156 SmallVector<StringRef, 4> Opts; 157 Spec.split(Opts, "+"); 158 for (int I = 0, E = Opts.size(); I != E; ++I) { 159 StringRef Opt = Opts[I].trim(); 160 if (Opt == "bti") { 161 PBP.BranchTargetEnforcement = true; 162 continue; 163 } 164 if (Opt == "pac-ret") { 165 PBP.Scope = "non-leaf"; 166 for (; I + 1 != E; ++I) { 167 StringRef PACOpt = Opts[I + 1].trim(); 168 if (PACOpt == "leaf") 169 PBP.Scope = "all"; 170 else if (PACOpt == "b-key") 171 PBP.Key = "b_key"; 172 else if (PACOpt == "pc") 173 PBP.BranchProtectionPAuthLR = true; 174 else 175 break; 176 } 177 continue; 178 } 179 if (Opt == "gcs") { 180 PBP.GuardedControlStack = true; 181 continue; 182 } 183 if (Opt == "") 184 Err = "<empty>"; 185 else 186 Err = Opt; 187 return false; 188 } 189 190 return true; 191 } 192