| 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(S: "v5" , Value: "v5t" ) |
| 22 | .Case(S: "v5e" , Value: "v5te" ) |
| 23 | .Case(S: "v6j" , Value: "v6" ) |
| 24 | .Case(S: "v6hl" , Value: "v6k" ) |
| 25 | .Cases(S0: "v6m" , S1: "v6sm" , S2: "v6s-m" , Value: "v6-m" ) |
| 26 | .Cases(S0: "v6z" , S1: "v6zk" , Value: "v6kz" ) |
| 27 | .Cases(S0: "v7" , S1: "v7a" , S2: "v7hl" , S3: "v7l" , Value: "v7-a" ) |
| 28 | .Case(S: "v7r" , Value: "v7-r" ) |
| 29 | .Case(S: "v7m" , Value: "v7-m" ) |
| 30 | .Case(S: "v7em" , Value: "v7e-m" ) |
| 31 | .Cases(S0: "v8" , S1: "v8a" , S2: "v8l" , S3: "aarch64" , S4: "arm64" , Value: "v8-a" ) |
| 32 | .Case(S: "v8.1a" , Value: "v8.1-a" ) |
| 33 | .Case(S: "v8.2a" , Value: "v8.2-a" ) |
| 34 | .Case(S: "v8.3a" , Value: "v8.3-a" ) |
| 35 | .Case(S: "v8.4a" , Value: "v8.4-a" ) |
| 36 | .Case(S: "v8.5a" , Value: "v8.5-a" ) |
| 37 | .Case(S: "v8.6a" , Value: "v8.6-a" ) |
| 38 | .Case(S: "v8.7a" , Value: "v8.7-a" ) |
| 39 | .Case(S: "v8.8a" , Value: "v8.8-a" ) |
| 40 | .Case(S: "v8.9a" , Value: "v8.9-a" ) |
| 41 | .Case(S: "v8r" , Value: "v8-r" ) |
| 42 | .Cases(S0: "v9" , S1: "v9a" , Value: "v9-a" ) |
| 43 | .Case(S: "v9.1a" , Value: "v9.1-a" ) |
| 44 | .Case(S: "v9.2a" , Value: "v9.2-a" ) |
| 45 | .Case(S: "v9.3a" , Value: "v9.3-a" ) |
| 46 | .Case(S: "v9.4a" , Value: "v9.4-a" ) |
| 47 | .Case(S: "v9.5a" , Value: "v9.5-a" ) |
| 48 | .Case(S: "v9.6a" , Value: "v9.6-a" ) |
| 49 | .Case(S: "v8m.base" , Value: "v8-m.base" ) |
| 50 | .Case(S: "v8m.main" , Value: "v8-m.main" ) |
| 51 | .Case(S: "v8.1m.main" , Value: "v8.1-m.main" ) |
| 52 | .Default(Value: 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(Prefix: "arm64_32" )) |
| 62 | offset = 8; |
| 63 | else if (A.starts_with(Prefix: "arm64e" )) |
| 64 | offset = 6; |
| 65 | else if (A.starts_with(Prefix: "arm64" )) |
| 66 | offset = 5; |
| 67 | else if (A.starts_with(Prefix: "aarch64_32" )) |
| 68 | offset = 10; |
| 69 | else if (A.starts_with(Prefix: "arm" )) |
| 70 | offset = 3; |
| 71 | else if (A.starts_with(Prefix: "thumb" )) |
| 72 | offset = 5; |
| 73 | else if (A.starts_with(Prefix: "aarch64" )) { |
| 74 | offset = 7; |
| 75 | // AArch64 uses "_be", not "eb" suffix. |
| 76 | if (A.contains(Other: "eb" )) |
| 77 | return Error; |
| 78 | if (A.substr(Start: offset, N: 3) == "_be" ) |
| 79 | offset += 3; |
| 80 | } |
| 81 | |
| 82 | // Ex. "armebv7", move past the "eb". |
| 83 | if (offset != StringRef::npos && A.substr(Start: offset, N: 2) == "eb" ) |
| 84 | offset += 2; |
| 85 | else |
| 86 | // Or, if it ends with eb ("armv7eb"), chop it off. |
| 87 | A.consume_back(Suffix: "eb" ); |
| 88 | // Trim the head |
| 89 | if (offset != StringRef::npos) |
| 90 | A = A.substr(Start: 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(Other: "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(S: "aarch64" , Value: ISAKind::AARCH64) |
| 113 | .StartsWith(S: "arm64" , Value: ISAKind::AARCH64) |
| 114 | .StartsWith(S: "thumb" , Value: ISAKind::THUMB) |
| 115 | .StartsWith(S: "arm" , Value: ISAKind::ARM) |
| 116 | .Default(Value: ISAKind::INVALID); |
| 117 | } |
| 118 | |
| 119 | ARM::EndianKind ARM::parseArchEndian(StringRef Arch) { |
| 120 | if (Arch.starts_with(Prefix: "armeb" ) || Arch.starts_with(Prefix: "thumbeb" ) || |
| 121 | Arch.starts_with(Prefix: "aarch64_be" )) |
| 122 | return EndianKind::BIG; |
| 123 | |
| 124 | if (Arch.starts_with(Prefix: "arm" ) || Arch.starts_with(Prefix: "thumb" )) { |
| 125 | if (Arch.ends_with(Suffix: "eb" )) |
| 126 | return EndianKind::BIG; |
| 127 | else |
| 128 | return EndianKind::LITTLE; |
| 129 | } |
| 130 | |
| 131 | if (Arch.starts_with(Prefix: "aarch64" ) || Arch.starts_with(Prefix: "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 = {.Scope: "none" , .Key: "a_key" , .BranchTargetEnforcement: false, .BranchProtectionPAuthLR: false, .GuardedControlStack: 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(A&: Opts, Separator: "+" ); |
| 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 | |