summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Target/ARM
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Target/ARM')
-rw-r--r--llvm/lib/Target/ARM/ARM.td5
-rw-r--r--llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp417
2 files changed, 289 insertions, 133 deletions
diff --git a/llvm/lib/Target/ARM/ARM.td b/llvm/lib/Target/ARM/ARM.td
index 25b9802f541..c1a3f639461 100644
--- a/llvm/lib/Target/ARM/ARM.td
+++ b/llvm/lib/Target/ARM/ARM.td
@@ -1022,6 +1022,10 @@ def ARMAsmWriter : AsmWriter {
bit isMCAsmWriter = 1;
}
+def ARMAsmParser : AsmParser {
+ bit ReportMultipleNearMisses = 1;
+}
+
def ARMAsmParserVariant : AsmParserVariant {
int Variant = 0;
string Name = "ARM";
@@ -1032,5 +1036,6 @@ def ARM : Target {
// Pull in Instruction Info.
let InstructionSet = ARMInstrInfo;
let AssemblyWriters = [ARMAsmWriter];
+ let AssemblyParsers = [ARMAsmParser];
let AssemblyParserVariants = [ARMAsmParserVariant];
}
diff --git a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
index b84a4e8b8e5..f2925f176a1 100644
--- a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
+++ b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
@@ -17,6 +17,7 @@
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/None.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
@@ -84,6 +85,11 @@ static cl::opt<ImplicitItModeTy> ImplicitItMode(
static cl::opt<bool> AddBuildAttributes("arm-add-build-attributes",
cl::init(false));
+cl::opt<bool>
+DevDiags("arm-asm-parser-dev-diags", cl::init(false),
+ cl::desc("Use extended diagnostics, which include implementation "
+ "details useful for development"));
+
enum VectorLaneTy { NoLanes, AllLanes, IndexedLane };
class UnwindContext {
@@ -608,8 +614,22 @@ public:
uint64_t &ErrorInfo,
bool MatchingInlineAsm) override;
unsigned MatchInstruction(OperandVector &Operands, MCInst &Inst,
- uint64_t &ErrorInfo, bool MatchingInlineAsm,
- bool &EmitInITBlock, MCStreamer &Out);
+ SmallVectorImpl<NearMissInfo> &NearMisses,
+ bool MatchingInlineAsm, bool &EmitInITBlock,
+ MCStreamer &Out);
+
+ struct NearMissMessage {
+ SMLoc Loc;
+ SmallString<128> Message;
+ };
+
+ const char *getOperandMatchFailDiag(ARMMatchResultTy Error);
+ void FilterNearMisses(SmallVectorImpl<NearMissInfo> &NearMissesIn,
+ SmallVectorImpl<NearMissMessage> &NearMissesOut,
+ SMLoc IDLoc, OperandVector &Operands);
+ void ReportNearMisses(SmallVectorImpl<NearMissInfo> &NearMisses, SMLoc IDLoc,
+ OperandVector &Operands);
+
void onLabelParsed(MCSymbol *Symbol) override;
};
@@ -8909,19 +8929,19 @@ bool ARMAsmParser::isITBlockTerminator(MCInst &Inst) const {
}
unsigned ARMAsmParser::MatchInstruction(OperandVector &Operands, MCInst &Inst,
- uint64_t &ErrorInfo,
+ SmallVectorImpl<NearMissInfo> &NearMisses,
bool MatchingInlineAsm,
bool &EmitInITBlock,
MCStreamer &Out) {
// If we can't use an implicit IT block here, just match as normal.
if (inExplicitITBlock() || !isThumbTwo() || !useImplicitITThumb())
- return MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm);
+ return MatchInstructionImpl(Operands, Inst, &NearMisses, MatchingInlineAsm);
// Try to match the instruction in an extension of the current IT block (if
// there is one).
if (inImplicitITBlock()) {
extendImplicitITBlock(ITState.Cond);
- if (MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm) ==
+ if (MatchInstructionImpl(Operands, Inst, nullptr, MatchingInlineAsm) ==
Match_Success) {
// The match succeded, but we still have to check that the instruction is
// valid in this implicit IT block.
@@ -8947,7 +8967,7 @@ unsigned ARMAsmParser::MatchInstruction(OperandVector &Operands, MCInst &Inst,
// Finish the current IT block, and try to match outside any IT block.
flushPendingInstructions(Out);
unsigned PlainMatchResult =
- MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm);
+ MatchInstructionImpl(Operands, Inst, &NearMisses, MatchingInlineAsm);
if (PlainMatchResult == Match_Success) {
const MCInstrDesc &MCID = MII.get(Inst.getOpcode());
if (MCID.isPredicable()) {
@@ -8974,7 +8994,7 @@ unsigned ARMAsmParser::MatchInstruction(OperandVector &Operands, MCInst &Inst,
// condition, so we create an IT block with a dummy condition, and fix it up
// once we know the actual condition.
startImplicitITBlock();
- if (MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm) ==
+ if (MatchInstructionImpl(Operands, Inst, nullptr, MatchingInlineAsm) ==
Match_Success) {
const MCInstrDesc &MCID = MII.get(Inst.getOpcode());
if (MCID.isPredicable()) {
@@ -9004,7 +9024,8 @@ bool ARMAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
unsigned MatchResult;
bool PendConditionalInstruction = false;
- MatchResult = MatchInstruction(Operands, Inst, ErrorInfo, MatchingInlineAsm,
+ SmallVector<NearMissInfo, 4> NearMisses;
+ MatchResult = MatchInstruction(Operands, Inst, NearMisses, MatchingInlineAsm,
PendConditionalInstruction, Out);
SMLoc ErrorLoc;
@@ -9061,33 +9082,9 @@ bool ARMAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
Out.EmitInstruction(Inst, getSTI());
}
return false;
- case Match_MissingFeature: {
- assert(ErrorInfo && "Unknown missing feature!");
- // Special case the error message for the very common case where only
- // a single subtarget feature is missing (Thumb vs. ARM, e.g.).
- std::string Msg = "instruction requires:";
- uint64_t Mask = 1;
- for (unsigned i = 0; i < (sizeof(ErrorInfo)*8-1); ++i) {
- if (ErrorInfo & Mask) {
- Msg += " ";
- Msg += getSubtargetFeatureName(ErrorInfo & Mask);
- }
- Mask <<= 1;
- }
- return Error(IDLoc, Msg);
- }
- case Match_InvalidOperand: {
- SMLoc ErrorLoc = IDLoc;
- if (ErrorInfo != ~0ULL) {
- if (ErrorInfo >= Operands.size())
- return Error(IDLoc, "too few operands for instruction");
-
- ErrorLoc = ((ARMOperand &)*Operands[ErrorInfo]).getStartLoc();
- if (ErrorLoc == SMLoc()) ErrorLoc = IDLoc;
- }
-
- return Error(ErrorLoc, "invalid operand for instruction");
- }
+ case Match_NearMisses:
+ ReportNearMisses(NearMisses, IDLoc, Operands);
+ return true;
case Match_MnemonicFail: {
uint64_t FBS = ComputeAvailableFeatures(getSTI().getFeatureBits());
std::string Suggestion = ARMMnemonicSpellCheck(
@@ -9095,104 +9092,6 @@ bool ARMAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
return Error(IDLoc, "invalid instruction" + Suggestion,
((ARMOperand &)*Operands[0]).getLocRange());
}
- case Match_RequiresNotITBlock:
- return Error(IDLoc, "flag setting instruction only valid outside IT block");
- case Match_RequiresITBlock:
- return Error(IDLoc, "instruction only valid inside IT block");
- case Match_RequiresV6:
- return Error(IDLoc, "instruction variant requires ARMv6 or later");
- case Match_RequiresThumb2:
- return Error(IDLoc, "instruction variant requires Thumb2");
- case Match_RequiresV8:
- return Error(IDLoc, "instruction variant requires ARMv8 or later");
- case Match_RequiresFlagSetting:
- return Error(IDLoc, "no flag-preserving variant of this instruction available");
- case Match_ImmRange0_1:
- return Error(ErrorLoc, "immediate operand must be in the range [0,1]");
- case Match_ImmRange0_3:
- return Error(ErrorLoc, "immediate operand must be in the range [0,3]");
- case Match_ImmRange0_7:
- return Error(ErrorLoc, "immediate operand must be in the range [0,7]");
- case Match_ImmRange0_15:
- return Error(ErrorLoc, "immediate operand must be in the range [0,15]");
- case Match_ImmRange0_31:
- return Error(ErrorLoc, "immediate operand must be in the range [0,31]");
- case Match_ImmRange0_32:
- return Error(ErrorLoc, "immediate operand must be in the range [0,32]");
- case Match_ImmRange0_63:
- return Error(ErrorLoc, "immediate operand must be in the range [0,63]");
- case Match_ImmRange0_239:
- return Error(ErrorLoc, "immediate operand must be in the range [0,239]");
- case Match_ImmRange0_255:
- return Error(ErrorLoc, "immediate operand must be in the range [0,255]");
- case Match_ImmRange0_4095:
- return Error(ErrorLoc, "immediate operand must be in the range [0,4095]");
- case Match_ImmRange0_65535:
- return Error(ErrorLoc, "immediate operand must be in the range [0,65535]");
- case Match_ImmRange1_7:
- return Error(ErrorLoc, "immediate operand must be in the range [1,7]");
- case Match_ImmRange1_8:
- return Error(ErrorLoc, "immediate operand must be in the range [1,8]");
- case Match_ImmRange1_15:
- return Error(ErrorLoc, "immediate operand must be in the range [1,15]");
- case Match_ImmRange1_16:
- return Error(ErrorLoc, "immediate operand must be in the range [1,16]");
- case Match_ImmRange1_31:
- return Error(ErrorLoc, "immediate operand must be in the range [1,31]");
- case Match_ImmRange1_32:
- return Error(ErrorLoc, "immediate operand must be in the range [1,32]");
- case Match_ImmRange1_64:
- return Error(ErrorLoc, "immediate operand must be in the range [1,64]");
- case Match_ImmRange8_8:
- return Error(ErrorLoc, "immediate operand must be 8.");
- case Match_ImmRange16_16:
- return Error(ErrorLoc, "immediate operand must be 16.");
- case Match_ImmRange32_32:
- return Error(ErrorLoc, "immediate operand must be 32.");
- case Match_ImmRange256_65535:
- return Error(ErrorLoc, "immediate operand must be in the range [255,65535]");
- case Match_ImmRange0_16777215:
- return Error(ErrorLoc, "immediate operand must be in the range [0,0xffffff]");
- case Match_AlignedMemoryRequiresNone:
- case Match_DupAlignedMemoryRequiresNone:
- case Match_AlignedMemoryRequires16:
- case Match_DupAlignedMemoryRequires16:
- case Match_AlignedMemoryRequires32:
- case Match_DupAlignedMemoryRequires32:
- case Match_AlignedMemoryRequires64:
- case Match_DupAlignedMemoryRequires64:
- case Match_AlignedMemoryRequires64or128:
- case Match_DupAlignedMemoryRequires64or128:
- case Match_AlignedMemoryRequires64or128or256:
- {
- SMLoc ErrorLoc = ((ARMOperand &)*Operands[ErrorInfo]).getAlignmentLoc();
- if (ErrorLoc == SMLoc()) ErrorLoc = IDLoc;
- switch (MatchResult) {
- default:
- llvm_unreachable("Missing Match_Aligned type");
- case Match_AlignedMemoryRequiresNone:
- case Match_DupAlignedMemoryRequiresNone:
- return Error(ErrorLoc, "alignment must be omitted");
- case Match_AlignedMemoryRequires16:
- case Match_DupAlignedMemoryRequires16:
- return Error(ErrorLoc, "alignment must be 16 or omitted");
- case Match_AlignedMemoryRequires32:
- case Match_DupAlignedMemoryRequires32:
- return Error(ErrorLoc, "alignment must be 32 or omitted");
- case Match_AlignedMemoryRequires64:
- case Match_DupAlignedMemoryRequires64:
- return Error(ErrorLoc, "alignment must be 64 or omitted");
- case Match_AlignedMemoryRequires64or128:
- case Match_DupAlignedMemoryRequires64or128:
- return Error(ErrorLoc, "alignment must be 64, 128 or omitted");
- case Match_AlignedMemoryRequires64or128or256:
- return Error(ErrorLoc, "alignment must be 64, 128, 256 or omitted");
- }
- }
- case Match_InvalidComplexRotationEven:
- return Error(IDLoc, "complex rotation must be 0, 90, 180 or 270");
- case Match_InvalidComplexRotationOdd:
- return Error(IDLoc, "complex rotation must be 90 or 270");
}
llvm_unreachable("Implement any new match types added!");
@@ -10203,6 +10102,258 @@ extern "C" void LLVMInitializeARMAsmParser() {
#define GET_MATCHER_IMPLEMENTATION
#include "ARMGenAsmMatcher.inc"
+const char *ARMAsmParser::getOperandMatchFailDiag(ARMMatchResultTy Error) {
+ switch (Error) {
+ case Match_AlignedMemoryRequiresNone:
+ case Match_DupAlignedMemoryRequiresNone:
+ return "alignment must be omitted";
+ case Match_AlignedMemoryRequires16:
+ case Match_DupAlignedMemoryRequires16:
+ return "alignment must be 16 or omitted";
+ case Match_AlignedMemoryRequires32:
+ case Match_DupAlignedMemoryRequires32:
+ return "alignment must be 32 or omitted";
+ case Match_AlignedMemoryRequires64:
+ case Match_DupAlignedMemoryRequires64:
+ return "alignment must be 64 or omitted";
+ case Match_AlignedMemoryRequires64or128:
+ case Match_DupAlignedMemoryRequires64or128:
+ return "alignment must be 64, 128 or omitted";
+ case Match_AlignedMemoryRequires64or128or256:
+ return "alignment must be 64, 128, 256 or omitted";
+ case Match_ImmRange0_1:
+ return "immediate operand must be in the range [0,1]";
+ case Match_ImmRange0_3:
+ return "immediate operand must be in the range [0,3]";
+ case Match_ImmRange0_7:
+ return "immediate operand must be in the range [0,7]";
+ case Match_ImmRange0_15:
+ return "immediate operand must be in the range [0,15]";
+ case Match_ImmRange0_31:
+ return "immediate operand must be in the range [0,31]";
+ case Match_ImmRange0_32:
+ return "immediate operand must be in the range [0,32]";
+ case Match_ImmRange0_63:
+ return "immediate operand must be in the range [0,63]";
+ case Match_ImmRange0_239:
+ return "immediate operand must be in the range [0,239]";
+ case Match_ImmRange0_255:
+ return "immediate operand must be in the range [0,255]";
+ case Match_ImmRange0_4095:
+ return "immediate operand must be in the range [0,4095]";
+ case Match_ImmRange0_65535:
+ return "immediate operand must be in the range [0,65535]";
+ case Match_ImmRange1_7:
+ return "immediate operand must be in the range [1,7]";
+ case Match_ImmRange1_8:
+ return "immediate operand must be in the range [1,8]";
+ case Match_ImmRange1_15:
+ return "immediate operand must be in the range [1,15]";
+ case Match_ImmRange1_16:
+ return "immediate operand must be in the range [1,16]";
+ case Match_ImmRange1_31:
+ return "immediate operand must be in the range [1,31]";
+ case Match_ImmRange1_32:
+ return "immediate operand must be in the range [1,32]";
+ case Match_ImmRange1_64:
+ return "immediate operand must be in the range [1,64]";
+ case Match_ImmRange8_8:
+ return "immediate operand must be 8.";
+ case Match_ImmRange16_16:
+ return "immediate operand must be 16.";
+ case Match_ImmRange32_32:
+ return "immediate operand must be 32.";
+ case Match_ImmRange256_65535:
+ return "immediate operand must be in the range [255,65535]";
+ case Match_ImmRange0_16777215:
+ return "immediate operand must be in the range [0,0xffffff]";
+ case Match_InvalidComplexRotationEven:
+ return "complex rotation must be 0, 90, 180 or 270";
+ case Match_InvalidComplexRotationOdd:
+ return "complex rotation must be 90 or 270";
+ default:
+ return nullptr;
+ }
+}
+
+// Process the list of near-misses, throwing away ones we don't want to report
+// to the user, and converting the rest to a source location and string that
+// should be reported.
+void
+ARMAsmParser::FilterNearMisses(SmallVectorImpl<NearMissInfo> &NearMissesIn,
+ SmallVectorImpl<NearMissMessage> &NearMissesOut,
+ SMLoc IDLoc, OperandVector &Operands) {
+ // TODO: If operand didn't match, sub in a dummy one and run target
+ // predicate, so that we can avoid reporting near-misses that are invalid?
+ // TODO: Many operand types dont have SuperClasses set, so we report
+ // redundant ones.
+ // TODO: Some operands are superclasses of registers (e.g.
+ // MCK_RegShiftedImm), we don't have any way to represent that currently.
+ // TODO: This is not all ARM-specific, can some of it be factored out?
+
+ // Record some information about near-misses that we have already seen, so
+ // that we can avoid reporting redundant ones. For example, if there are
+ // variants of an instruction that take 8- and 16-bit immediates, we want
+ // to only report the widest one.
+ std::multimap<unsigned, unsigned> OperandMissesSeen;
+ SmallSet<uint64_t, 4> FeatureMissesSeen;
+
+ // Process the near-misses in reverse order, so that we see more general ones
+ // first, and so can avoid emitting more specific ones.
+ for (NearMissInfo &I : reverse(NearMissesIn)) {
+ switch (I.getKind()) {
+ case NearMissInfo::NearMissOperand: {
+ SMLoc OperandLoc =
+ ((ARMOperand &)*Operands[I.getOperandIndex()]).getStartLoc();
+ const char *OperandDiag =
+ getOperandMatchFailDiag((ARMMatchResultTy)I.getOperandError());
+
+ // If we have already emitted a message for a superclass, don't also report
+ // the sub-class. We consider all operand classes that we don't have a
+ // specialised diagnostic for to be equal for the propose of this check,
+ // so that we don't report the generic error multiple times on the same
+ // operand.
+ unsigned DupCheckMatchClass = OperandDiag ? I.getOperandClass() : ~0U;
+ auto PrevReports = OperandMissesSeen.equal_range(I.getOperandIndex());
+ if (std::any_of(PrevReports.first, PrevReports.second,
+ [DupCheckMatchClass](
+ const std::pair<unsigned, unsigned> Pair) {
+ if (DupCheckMatchClass == ~0U)
+ return Pair.second == ~0U;
+ else
+ return isSubclass((MatchClassKind)DupCheckMatchClass,
+ (MatchClassKind)Pair.second);
+ }))
+ break;
+ OperandMissesSeen.insert(
+ std::make_pair(I.getOperandIndex(), DupCheckMatchClass));
+
+ NearMissMessage Message;
+ Message.Loc = OperandLoc;
+ raw_svector_ostream OS(Message.Message);
+ if (OperandDiag) {
+ OS << OperandDiag;
+ } else if (I.getOperandClass() == InvalidMatchClass) {
+ OS << "too many operands for instruction";
+ } else {
+ OS << "invalid operand for instruction";
+ if (DevDiags) {
+ OS << " class" << I.getOperandClass() << ", error "
+ << I.getOperandError() << ", opcode "
+ << MII.getName(I.getOpcode());
+ }
+ }
+ NearMissesOut.emplace_back(Message);
+ break;
+ }
+ case NearMissInfo::NearMissFeature: {
+ uint64_t MissingFeatures = I.getFeatures();
+ // Don't report the same set of features twice.
+ if (FeatureMissesSeen.count(MissingFeatures))
+ break;
+ FeatureMissesSeen.insert(MissingFeatures);
+
+ // Special case: don't report a feature set which includes arm-mode for
+ // targets that don't have ARM mode.
+ if ((MissingFeatures & Feature_IsARM) && !hasARM())
+ break;
+ // Don't report any near-misses that both require switching instruction
+ // set, and adding other subtarget features.
+ if (isThumb() && (MissingFeatures & Feature_IsARM) &&
+ (MissingFeatures & ~Feature_IsARM))
+ break;
+ if (!isThumb() && (MissingFeatures & Feature_IsThumb) &&
+ (MissingFeatures & ~Feature_IsThumb))
+ break;
+ if (!isThumb() && (MissingFeatures & Feature_IsThumb2) &&
+ (MissingFeatures & ~(Feature_IsThumb2 | Feature_IsThumb)))
+ break;
+
+ NearMissMessage Message;
+ Message.Loc = IDLoc;
+ raw_svector_ostream OS(Message.Message);
+
+ OS << "instruction requires:";
+ uint64_t Mask = 1;
+ for (unsigned MaskPos = 0; MaskPos < (sizeof(MissingFeatures) * 8 - 1);
+ ++MaskPos) {
+ if (MissingFeatures & Mask) {
+ OS << " " << getSubtargetFeatureName(MissingFeatures & Mask);
+ }
+ Mask <<= 1;
+ }
+ NearMissesOut.emplace_back(Message);
+
+ break;
+ }
+ case NearMissInfo::NearMissPredicate: {
+ NearMissMessage Message;
+ Message.Loc = IDLoc;
+ switch (I.getPredicateError()) {
+ case Match_RequiresNotITBlock:
+ Message.Message = "flag setting instruction only valid outside IT block";
+ break;
+ case Match_RequiresITBlock:
+ Message.Message = "instruction only valid inside IT block";
+ break;
+ case Match_RequiresV6:
+ Message.Message = "instruction variant requires ARMv6 or later";
+ break;
+ case Match_RequiresThumb2:
+ Message.Message = "instruction variant requires Thumb2";
+ break;
+ case Match_RequiresV8:
+ Message.Message = "instruction variant requires ARMv8 or later";
+ break;
+ case Match_RequiresFlagSetting:
+ Message.Message = "no flag-preserving variant of this instruction available";
+ break;
+ case Match_InvalidOperand:
+ Message.Message = "invalid operand for instruction";
+ break;
+ default:
+ llvm_unreachable("Unhandled target predicate error");
+ break;
+ }
+ NearMissesOut.emplace_back(Message);
+ break;
+ }
+ case NearMissInfo::NearMissTooFewOperands: {
+ SMLoc EndLoc = ((ARMOperand &)*Operands.back()).getEndLoc();
+ NearMissesOut.emplace_back(
+ NearMissMessage{ EndLoc, StringRef("too few operands for instruction") });
+ break;
+ }
+ case NearMissInfo::NoNearMiss:
+ // This should never leave the matcher.
+ llvm_unreachable("not a near-miss");
+ break;
+ }
+ }
+}
+
+void ARMAsmParser::ReportNearMisses(SmallVectorImpl<NearMissInfo> &NearMisses,
+ SMLoc IDLoc, OperandVector &Operands) {
+ SmallVector<NearMissMessage, 4> Messages;
+ FilterNearMisses(NearMisses, Messages, IDLoc, Operands);
+
+ if (Messages.size() == 0) {
+ // No near-misses were found, so the best we can do is "invalid
+ // instruction".
+ Error(IDLoc, "invalid instruction");
+ } else if (Messages.size() == 1) {
+ // One near miss was found, report it as the sole error.
+ Error(Messages[0].Loc, Messages[0].Message);
+ } else {
+ // More than one near miss, so report a generic "invalid instruction"
+ // error, followed by notes for each of the near-misses.
+ Error(IDLoc, "invalid instruction, any one of the following would fix this:");
+ for (auto &M : Messages) {
+ Note(M.Loc, M.Message);
+ }
+ }
+}
+
// FIXME: This structure should be moved inside ARMTargetParser
// when we start to table-generate them, and we can use the ARM
// flags below, that were generated by table-gen.
OpenPOWER on IntegriCloud