diff options
-rw-r--r-- | include/llvm/Target/Target.td | 5 | ||||
-rw-r--r-- | lib/Target/AArch64/AArch64InstrFormats.td | 6 | ||||
-rw-r--r-- | lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp | 5 | ||||
-rw-r--r-- | test/MC/AArch64/basic-a64-diagnostics.s | 20 | ||||
-rw-r--r-- | test/MC/Disassembler/AArch64/basic-a64-instructions.txt | 22 | ||||
-rw-r--r-- | utils/TableGen/AsmWriterEmitter.cpp | 49 |
6 files changed, 101 insertions, 6 deletions
diff --git a/include/llvm/Target/Target.td b/include/llvm/Target/Target.td index 7d1f19c477..f77cc7a35e 100644 --- a/include/llvm/Target/Target.td +++ b/include/llvm/Target/Target.td @@ -587,6 +587,11 @@ class Operand<ValueType ty> : DAGOperand { string OperandType = "OPERAND_UNKNOWN"; dag MIOperandInfo = (ops); + // MCOperandPredicate - Optionally, a code fragment operating on + // const MCOperand &MCOp, and returning a bool, to indicate if + // the value of MCOp is valid for the specific subclass of Operand + code MCOperandPredicate; + // ParserMatchClass - The "match class" that operands of this type fit // in. Match classes are used to define the order in which instructions are // match, to ensure that which instructions gets matched is deterministic. diff --git a/lib/Target/AArch64/AArch64InstrFormats.td b/lib/Target/AArch64/AArch64InstrFormats.td index 42326fc182..446149b4fb 100644 --- a/lib/Target/AArch64/AArch64InstrFormats.td +++ b/lib/Target/AArch64/AArch64InstrFormats.td @@ -963,8 +963,14 @@ def ccode : Operand<i32> { let ParserMatchClass = CondCode; } def inv_ccode : Operand<i32> { + // AL and NV are invalid in the aliases which use inv_ccode let PrintMethod = "printInverseCondCode"; let ParserMatchClass = CondCode; + let MCOperandPredicate = [{ + return MCOp.isImm() && + MCOp.getImm() != AArch64CC::AL && + MCOp.getImm() != AArch64CC::NV; + }]; } // Conditional branch target. 19-bit immediate. The low two bits of the target diff --git a/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp index 7d22b11ad9..f861df0bf9 100644 --- a/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp +++ b/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp @@ -2184,8 +2184,11 @@ bool AArch64AsmParser::parseCondCode(OperandVector &Operands, return TokError("invalid condition code"); Parser.Lex(); // Eat identifier token. - if (invertCondCode) + if (invertCondCode) { + if (CC == AArch64CC::AL || CC == AArch64CC::NV) + return TokError("condition codes AL and NV are invalid for this instruction"); CC = AArch64CC::getInvertedCondCode(AArch64CC::CondCode(CC)); + } Operands.push_back( AArch64Operand::CreateCondCode(CC, S, getLoc(), getContext())); diff --git a/test/MC/AArch64/basic-a64-diagnostics.s b/test/MC/AArch64/basic-a64-diagnostics.s index a4a3b1379c..b33891cc3d 100644 --- a/test/MC/AArch64/basic-a64-diagnostics.s +++ b/test/MC/AArch64/basic-a64-diagnostics.s @@ -1345,39 +1345,59 @@ cset wsp, lt csetm sp, ge + cset w1, al + csetm x6, nv // CHECK-ERROR: error: invalid operand for instruction // CHECK-ERROR-NEXT: cset wsp, lt // CHECK-ERROR-NEXT: ^ // CHECK-ERROR-NEXT: error: invalid operand for instruction // CHECK-ERROR-NEXT: csetm sp, ge // CHECK-ERROR-NEXT: ^ +// CHECK-ERROR-NEXT: error: condition codes AL and NV are invalid for this instruction +// CHECK-ERROR-NEXT: cset w1, al +// CHECK-ERROR-NEXT: ^ +// CHECK-ERROR-NEXT: error: condition codes AL and NV are invalid for this instruction +// CHECK-ERROR-NEXT: csetm x6, nv +// CHECK-ERROR-NEXT: ^ cinc w3, wsp, ne cinc sp, x9, eq + cinc x2, x0, nv // CHECK-ERROR: error: invalid operand for instruction // CHECK-ERROR-NEXT: cinc w3, wsp, ne // CHECK-ERROR-NEXT: ^ // CHECK-ERROR-NEXT: error: invalid operand for instruction // CHECK-ERROR-NEXT: cinc sp, x9, eq // CHECK-ERROR-NEXT: ^ +// CHECK-ERROR-NEXT: error: condition codes AL and NV are invalid for this instruction +// CHECK-ERROR-NEXT: cinc x2, x0, nv +// CHECK-ERROR-NEXT: ^ cinv w3, wsp, ne cinv sp, x9, eq + cinv w8, x7, nv // CHECK-ERROR: error: invalid operand for instruction // CHECK-ERROR-NEXT: cinv w3, wsp, ne // CHECK-ERROR-NEXT: ^ // CHECK-ERROR-NEXT: error: invalid operand for instruction // CHECK-ERROR-NEXT: cinv sp, x9, eq // CHECK-ERROR-NEXT: ^ +// CHECK-ERROR-NEXT: error: condition codes AL and NV are invalid for this instruction +// CHECK-ERROR-NEXT: cinv w8, x7, nv +// CHECK-ERROR-NEXT: ^ cneg w3, wsp, ne cneg sp, x9, eq + cneg x4, x5, al // CHECK-ERROR: error: invalid operand for instruction // CHECK-ERROR-NEXT: cneg w3, wsp, ne // CHECK-ERROR-NEXT: ^ // CHECK-ERROR-NEXT: error: invalid operand for instruction // CHECK-ERROR-NEXT: cneg sp, x9, eq // CHECK-ERROR-NEXT: ^ +// CHECK-ERROR-NEXT: error: condition codes AL and NV are invalid for this instruction +// CHECK-ERROR-NEXT: cneg x4, x5, al +// CHECK-ERROR-NEXT: ^ //------------------------------------------------------------------------------ // Data Processing (1 source) diff --git a/test/MC/Disassembler/AArch64/basic-a64-instructions.txt b/test/MC/Disassembler/AArch64/basic-a64-instructions.txt index 70c45c8513..23da001acc 100644 --- a/test/MC/Disassembler/AArch64/basic-a64-instructions.txt +++ b/test/MC/Disassembler/AArch64/basic-a64-instructions.txt @@ -945,10 +945,15 @@ # CHECK: cset x9, pl # CHECK: csetm w20, ne # CHECK: csetm x30, ge +# "cset w2, nv" and "csetm x3, al" are invalid aliases for these two +# CHECK: csinc w2, wzr, wzr, al +# CHECK: csinv x3, xzr, xzr, nv 0xe3 0x17 0x9f 0x1a 0xe9 0x47 0x9f 0x9a 0xf4 0x3 0x9f 0x5a 0xfe 0xb3 0x9f 0xda +0xe2,0xe7,0x9f,0x1a +0xe3,0xf3,0x9f,0xda # CHECK: cinc w3, w5, gt # CHECK: cinc wzr, w4, le @@ -956,12 +961,17 @@ # CHECK: cinc x3, x5, gt # CHECK: cinc xzr, x4, le # CHECK: cset x9, lt +# "cinc w5, w6, al" and "cinc x1, x2, nv" are invalid aliases for these two +# CHECK: csinc w5, w6, w6, nv +# CHECK: csinc x1, x2, x2, al 0xa3 0xd4 0x85 0x1a 0x9f 0xc4 0x84 0x1a 0xe9 0xa7 0x9f 0x1a 0xa3 0xd4 0x85 0x9a 0x9f 0xc4 0x84 0x9a 0xe9 0xa7 0x9f 0x9a +0xc5,0xf4,0x86,0x1a +0x41,0xe4,0x82,0x9a # CHECK: cinv w3, w5, gt # CHECK: cinv wzr, w4, le @@ -969,14 +979,17 @@ # CHECK: cinv x3, x5, gt # CHECK: cinv xzr, x4, le # CHECK: csetm x9, lt -# CHECK: cinv x0, x0, nv +# "cinv x1, x0, nv" and "cinv w9, w8, al" are invalid aliases for these two +# CHECK: csinv x1, x0, x0, al +# CHECK: csinv w9, w8, w8, nv 0xa3 0xd0 0x85 0x5a 0x9f 0xc0 0x84 0x5a 0xe9 0xa3 0x9f 0x5a 0xa3 0xd0 0x85 0xda 0x9f 0xc0 0x84 0xda 0xe9 0xa3 0x9f 0xda -0x00 0xe0 0x80 0xda +0x01 0xe0 0x80 0xda +0x09,0xf1,0x88,0x5a # CHECK: cneg w3, w5, gt # CHECK: cneg wzr, w4, le @@ -984,12 +997,17 @@ # CHECK: cneg x3, x5, gt # CHECK: cneg xzr, x4, le # CHECK: cneg x9, xzr, lt +# "cneg x4, x8, nv" and "cneg w5, w6, al" are invalid aliases for these two +# CHECK: csneg x4, x8, x8, al +# CHECK: csinv w9, w8, w8, nv 0xa3 0xd4 0x85 0x5a 0x9f 0xc4 0x84 0x5a 0xe9 0xa7 0x9f 0x5a 0xa3 0xd4 0x85 0xda 0x9f 0xc4 0x84 0xda 0xe9 0xa7 0x9f 0xda +0x04,0xe5,0x88,0xda +0x09,0xf1,0x88,0x5a #------------------------------------------------------------------------------ # Data-processing (1 source) diff --git a/utils/TableGen/AsmWriterEmitter.cpp b/utils/TableGen/AsmWriterEmitter.cpp index 2bd9f80540..c7fe9dfd68 100644 --- a/utils/TableGen/AsmWriterEmitter.cpp +++ b/utils/TableGen/AsmWriterEmitter.cpp @@ -806,6 +806,10 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) { // before it can be matched to the mnemonic. std::map<std::string, std::vector<IAPrinter*> > IAPrinterMap; + // A list of MCOperandPredicates for all operands in use, and the reverse map + std::vector<const Record*> MCOpPredicates; + DenseMap<const Record*, unsigned> MCOpPredicateMap; + for (auto &Aliases : AliasMap) { for (auto &Alias : Aliases.second) { const CodeGenInstAlias *CGA = Alias.first; @@ -870,18 +874,30 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) { Cond = std::string("MRI.getRegClass(") + Target.getName() + "::" + R->getName() + "RegClassID)" ".contains(" + Op + ".getReg())"; - IAP->addCond(Cond); } else { Cond = Op + ".getReg() == MI->getOperand(" + llvm::utostr(IAP->getOpIndex(ROName)) + ").getReg()"; - IAP->addCond(Cond); } } else { // Assume all printable operands are desired for now. This can be // overridden in the InstAlias instantiation if necessary. IAP->addOperand(ROName, MIOpNum, PrintMethodIdx); - } + // There might be an additional predicate on the MCOperand + unsigned Entry = MCOpPredicateMap[Rec]; + if (!Entry) { + if (!Rec->isValueUnset("MCOperandPredicate")) { + MCOpPredicates.push_back(Rec); + Entry = MCOpPredicates.size(); + MCOpPredicateMap[Rec] = Entry; + } else + break; // No conditions on this operand at all + } + Cond = Target.getName() + ClassName + "ValidateMCOperand(" + + Op + ", " + llvm::utostr(Entry) + ")"; + } + // for all subcases of ResultOperand::K_Record: + IAP->addCond(Cond); break; } case CodeGenInstAlias::ResultOperand::K_Imm: { @@ -975,6 +991,11 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) { return; } + if (MCOpPredicates.size()) + O << "static bool " << Target.getName() << ClassName + << "ValidateMCOperand(\n" + << " const MCOperand &MCOp, unsigned PredicateIndex);\n"; + O << HeaderO.str(); O.indent(2) << "const char *AsmString;\n"; O.indent(2) << "switch (MI->getOpcode()) {\n"; @@ -1036,6 +1057,28 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) { } O << "}\n\n"; + if (MCOpPredicates.size()) { + O << "static bool " << Target.getName() << ClassName + << "ValidateMCOperand(\n" + << " const MCOperand &MCOp, unsigned PredicateIndex) {\n" + << " switch (PredicateIndex) {\n" + << " default:\n" + << " llvm_unreachable(\"Unknown MCOperandPredicate kind\");\n" + << " break;\n"; + + for (unsigned i = 0; i < MCOpPredicates.size(); ++i) { + Init *MCOpPred = MCOpPredicates[i]->getValueInit("MCOperandPredicate"); + if (StringInit *SI = dyn_cast<StringInit>(MCOpPred)) { + O << " case " << i + 1 << ": {\n" + << SI->getValue() << "\n" + << " }\n"; + } else + llvm_unreachable("Unexpected MCOperandPredicate field!"); + } + O << " }\n" + << "}\n\n"; + } + O << "#endif // PRINT_ALIAS_INSTR\n"; } |