| //===---------------- ARMTargetParserCommon ---------------------*- C++ -*-===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| // | |
| // Code that is common to ARMTargetParser and AArch64TargetParser. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "llvm/TargetParser/ARMTargetParserCommon.h" | |
| #include "llvm/ADT/SmallVector.h" | |
| #include "llvm/ADT/StringSwitch.h" | |
| using namespace llvm; | |
| StringRef ARM::getArchSynonym(StringRef Arch) { | |
| return StringSwitch<StringRef>(Arch) | |
| .Case("v5", "v5t") | |
| .Case("v5e", "v5te") | |
| .Case("v6j", "v6") | |
| .Case("v6hl", "v6k") | |
| .Cases("v6m", "v6sm", "v6s-m", "v6-m") | |
| .Cases("v6z", "v6zk", "v6kz") | |
| .Cases("v7", "v7a", "v7hl", "v7l", "v7-a") | |
| .Case("v7r", "v7-r") | |
| .Case("v7m", "v7-m") | |
| .Case("v7em", "v7e-m") | |
| .Cases("v8", "v8a", "v8l", "aarch64", "arm64", "v8-a") | |
| .Case("v8.1a", "v8.1-a") | |
| .Case("v8.2a", "v8.2-a") | |
| .Case("v8.3a", "v8.3-a") | |
| .Case("v8.4a", "v8.4-a") | |
| .Case("v8.5a", "v8.5-a") | |
| .Case("v8.6a", "v8.6-a") | |
| .Case("v8.7a", "v8.7-a") | |
| .Case("v8.8a", "v8.8-a") | |
| .Case("v8.9a", "v8.9-a") | |
| .Case("v8r", "v8-r") | |
| .Cases("v9", "v9a", "v9-a") | |
| .Case("v9.1a", "v9.1-a") | |
| .Case("v9.2a", "v9.2-a") | |
| .Case("v9.3a", "v9.3-a") | |
| .Case("v9.4a", "v9.4-a") | |
| .Case("v8m.base", "v8-m.base") | |
| .Case("v8m.main", "v8-m.main") | |
| .Case("v8.1m.main", "v8.1-m.main") | |
| .Default(Arch); | |
| } | |
| StringRef ARM::getCanonicalArchName(StringRef Arch) { | |
| size_t offset = StringRef::npos; | |
| StringRef A = Arch; | |
| StringRef Error = ""; | |
| // Begins with "arm" / "thumb", move past it. | |
| if (A.startswith("arm64_32")) | |
| offset = 8; | |
| else if (A.startswith("arm64e")) | |
| offset = 6; | |
| else if (A.startswith("arm64")) | |
| offset = 5; | |
| else if (A.startswith("aarch64_32")) | |
| offset = 10; | |
| else if (A.startswith("arm")) | |
| offset = 3; | |
| else if (A.startswith("thumb")) | |
| offset = 5; | |
| else if (A.startswith("aarch64")) { | |
| offset = 7; | |
| // AArch64 uses "_be", not "eb" suffix. | |
| if (A.contains("eb")) | |
| return Error; | |
| if (A.substr(offset, 3) == "_be") | |
| offset += 3; | |
| } | |
| // Ex. "armebv7", move past the "eb". | |
| if (offset != StringRef::npos && A.substr(offset, 2) == "eb") | |
| offset += 2; | |
| // Or, if it ends with eb ("armv7eb"), chop it off. | |
| else if (A.endswith("eb")) | |
| A = A.substr(0, A.size() - 2); | |
| // Trim the head | |
| if (offset != StringRef::npos) | |
| A = A.substr(offset); | |
| // Empty string means offset reached the end, which means it's valid. | |
| if (A.empty()) | |
| return Arch; | |
| // Only match non-marketing names | |
| if (offset != StringRef::npos) { | |
| // Must start with 'vN'. | |
| if (A.size() >= 2 && (A[0] != 'v' || !std::isdigit(A[1]))) | |
| return Error; | |
| // Can't have an extra 'eb'. | |
| if (A.contains("eb")) | |
| return Error; | |
| } | |
| // Arch will either be a 'v' name (v7a) or a marketing name (xscale). | |
| return A; | |
| } | |
| ARM::ISAKind ARM::parseArchISA(StringRef Arch) { | |
| return StringSwitch<ISAKind>(Arch) | |
| .StartsWith("aarch64", ISAKind::AARCH64) | |
| .StartsWith("arm64", ISAKind::AARCH64) | |
| .StartsWith("thumb", ISAKind::THUMB) | |
| .StartsWith("arm", ISAKind::ARM) | |
| .Default(ISAKind::INVALID); | |
| } | |
| ARM::EndianKind ARM::parseArchEndian(StringRef Arch) { | |
| if (Arch.startswith("armeb") || Arch.startswith("thumbeb") || | |
| Arch.startswith("aarch64_be")) | |
| return EndianKind::BIG; | |
| if (Arch.startswith("arm") || Arch.startswith("thumb")) { | |
| if (Arch.endswith("eb")) | |
| return EndianKind::BIG; | |
| else | |
| return EndianKind::LITTLE; | |
| } | |
| if (Arch.startswith("aarch64") || Arch.startswith("aarch64_32")) | |
| return EndianKind::LITTLE; | |
| return EndianKind::INVALID; | |
| } | |
| // Parse a branch protection specification, which has the form | |
| // standard | none | [bti,pac-ret[+b-key,+leaf]*] | |
| // Returns true on success, with individual elements of the specification | |
| // returned in `PBP`. Returns false in error, with `Err` containing | |
| // an erroneous part of the spec. | |
| bool ARM::parseBranchProtection(StringRef Spec, ParsedBranchProtection &PBP, | |
| StringRef &Err) { | |
| PBP = {"none", "a_key", false}; | |
| if (Spec == "none") | |
| return true; // defaults are ok | |
| if (Spec == "standard") { | |
| PBP.Scope = "non-leaf"; | |
| PBP.BranchTargetEnforcement = true; | |
| return true; | |
| } | |
| SmallVector<StringRef, 4> Opts; | |
| Spec.split(Opts, "+"); | |
| for (int I = 0, E = Opts.size(); I != E; ++I) { | |
| StringRef Opt = Opts[I].trim(); | |
| if (Opt == "bti") { | |
| PBP.BranchTargetEnforcement = true; | |
| continue; | |
| } | |
| if (Opt == "pac-ret") { | |
| PBP.Scope = "non-leaf"; | |
| for (; I + 1 != E; ++I) { | |
| StringRef PACOpt = Opts[I + 1].trim(); | |
| if (PACOpt == "leaf") | |
| PBP.Scope = "all"; | |
| else if (PACOpt == "b-key") | |
| PBP.Key = "b_key"; | |
| else | |
| break; | |
| } | |
| continue; | |
| } | |
| if (Opt == "") | |
| Err = "<empty>"; | |
| else | |
| Err = Opt; | |
| return false; | |
| } | |
| return true; | |
| } |