From: Owen Anderson Date: Thu, 13 Jan 2011 21:46:02 +0000 (+0000) Subject: Add support to the ARM MC infrastructure to support mcr and friends. This requires... X-Git-Url: http://plrg.eecs.uci.edu/git/?a=commitdiff_plain;h=e4e5e2aae7e1e0e84877061432e7b981a360a77d;p=oota-llvm.git Add support to the ARM MC infrastructure to support mcr and friends. This requires supporting the symbolic immediate names used for these instructions, fixing their pretty-printers, and adding proper encoding information for them. With this, we can properly pretty-print and encode assembly like: mrc p15, #0, r3, c13, c0, #3 Fixes . git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@123404 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Target/ARM/ARMInstrInfo.td b/lib/Target/ARM/ARMInstrInfo.td index c615ad9d0f7..4024482b1b8 100644 --- a/lib/Target/ARM/ARMInstrInfo.td +++ b/lib/Target/ARM/ARMInstrInfo.td @@ -561,6 +561,14 @@ def nohash_imm : Operand { let PrintMethod = "printNoHashImmediate"; } +def p_imm : Operand { + let PrintMethod = "printPImmediate"; +} + +def c_imm : Operand { + let PrintMethod = "printCImmediate"; +} + //===----------------------------------------------------------------------===// include "ARMInstrFormats.td" @@ -3598,68 +3606,172 @@ defm LDC2 : LdStCop<0b1111, 1, "ldc2">; defm STC : LdStCop<{?,?,?,?}, 0, "stc">; defm STC2 : LdStCop<0b1111, 0, "stc2">; -def MCR : ABI<0b1110, (outs), (ins nohash_imm:$cop, i32imm:$opc1, - GPR:$Rt, nohash_imm:$CRn, nohash_imm:$CRm, i32imm:$opc2), - NoItinerary, "mcr", "\tp$cop, $opc1, $Rt, cr$CRn, cr$CRm, $opc2", +def MCR : ABI<0b1110, (outs), (ins p_imm:$cop, i32imm:$opc1, + GPR:$Rt, c_imm:$CRn, c_imm:$CRm, i32imm:$opc2), + NoItinerary, "mcr", "\t$cop, $opc1, $Rt, $CRn, $CRm, $opc2", [/* For disassembly only; pattern left blank */]> { let Inst{20} = 0; let Inst{4} = 1; + + bits<4> Rt; + bits<4> cop; + bits<3> opc1; + bits<3> opc2; + bits<4> CRm; + bits<4> CRn; + + let Inst{15-12} = Rt; + let Inst{11-8} = cop; + let Inst{23-21} = opc1; + let Inst{7-5} = opc2; + let Inst{3-0} = CRm; + let Inst{19-16} = CRn; } -def MCR2 : ABXI<0b1110, (outs), (ins nohash_imm:$cop, i32imm:$opc1, - GPR:$Rt, nohash_imm:$CRn, nohash_imm:$CRm, i32imm:$opc2), - NoItinerary, "mcr2\tp$cop, $opc1, $Rt, cr$CRn, cr$CRm, $opc2", +def MCR2 : ABXI<0b1110, (outs), (ins p_imm:$cop, i32imm:$opc1, + GPR:$Rt, c_imm:$CRn, c_imm:$CRm, i32imm:$opc2), + NoItinerary, "mcr2\t$cop, $opc1, $Rt, $CRn, $CRm, $opc2", [/* For disassembly only; pattern left blank */]> { let Inst{31-28} = 0b1111; let Inst{20} = 0; let Inst{4} = 1; + + bits<4> Rt; + bits<4> cop; + bits<3> opc1; + bits<3> opc2; + bits<4> CRm; + bits<4> CRn; + + let Inst{15-12} = Rt; + let Inst{11-8} = cop; + let Inst{23-21} = opc1; + let Inst{7-5} = opc2; + let Inst{3-0} = CRm; + let Inst{19-16} = CRn; } -def MRC : ABI<0b1110, (outs), (ins nohash_imm:$cop, i32imm:$opc1, - GPR:$Rt, nohash_imm:$CRn, nohash_imm:$CRm, i32imm:$opc2), - NoItinerary, "mrc", "\tp$cop, $opc1, $Rt, cr$CRn, cr$CRm, $opc2", +def MRC : ABI<0b1110, (outs), (ins p_imm:$cop, i32imm:$opc1, + GPR:$Rt, c_imm:$CRn, c_imm:$CRm, i32imm:$opc2), + NoItinerary, "mrc", "\t$cop, $opc1, $Rt, $CRn, $CRm, $opc2", [/* For disassembly only; pattern left blank */]> { let Inst{20} = 1; let Inst{4} = 1; + + bits<4> Rt; + bits<4> cop; + bits<3> opc1; + bits<3> opc2; + bits<4> CRm; + bits<4> CRn; + + let Inst{15-12} = Rt; + let Inst{11-8} = cop; + let Inst{23-21} = opc1; + let Inst{7-5} = opc2; + let Inst{3-0} = CRm; + let Inst{19-16} = CRn; } -def MRC2 : ABXI<0b1110, (outs), (ins nohash_imm:$cop, i32imm:$opc1, - GPR:$Rt, nohash_imm:$CRn, nohash_imm:$CRm, i32imm:$opc2), - NoItinerary, "mrc2\tp$cop, $opc1, $Rt, cr$CRn, cr$CRm, $opc2", +def MRC2 : ABXI<0b1110, (outs), (ins p_imm:$cop, i32imm:$opc1, + GPR:$Rt, c_imm:$CRn, c_imm:$CRm, i32imm:$opc2), + NoItinerary, "mrc2\t$cop, $opc1, $Rt, $CRn, $CRm, $opc2", [/* For disassembly only; pattern left blank */]> { let Inst{31-28} = 0b1111; let Inst{20} = 1; let Inst{4} = 1; + + bits<4> Rt; + bits<4> cop; + bits<3> opc1; + bits<3> opc2; + bits<4> CRm; + bits<4> CRn; + + let Inst{15-12} = Rt; + let Inst{11-8} = cop; + let Inst{23-21} = opc1; + let Inst{7-5} = opc2; + let Inst{3-0} = CRm; + let Inst{19-16} = CRn; } -def MCRR : ABI<0b1100, (outs), (ins nohash_imm:$cop, i32imm:$opc, - GPR:$Rt, GPR:$Rt2, nohash_imm:$CRm), - NoItinerary, "mcrr", "\tp$cop, $opc, $Rt, $Rt2, cr$CRm", +def MCRR : ABI<0b1100, (outs), (ins p_imm:$cop, i32imm:$opc, + GPR:$Rt, GPR:$Rt2, c_imm:$CRm), + NoItinerary, "mcrr", "\t$cop, $opc, $Rt, $Rt2, $CRm", [/* For disassembly only; pattern left blank */]> { let Inst{23-20} = 0b0100; + + bits<4> Rt; + bits<4> Rt2; + bits<4> cop; + bits<3> opc1; + bits<4> CRm; + + let Inst{15-12} = Rt; + let Inst{19-16} = Rt2; + let Inst{11-8} = cop; + let Inst{7-5} = opc1; + let Inst{3-0} = CRm; } -def MCRR2 : ABXI<0b1100, (outs), (ins nohash_imm:$cop, i32imm:$opc, - GPR:$Rt, GPR:$Rt2, nohash_imm:$CRm), - NoItinerary, "mcrr2\tp$cop, $opc, $Rt, $Rt2, cr$CRm", +def MCRR2 : ABXI<0b1100, (outs), (ins p_imm:$cop, i32imm:$opc, + GPR:$Rt, GPR:$Rt2, c_imm:$CRm), + NoItinerary, "mcrr2\t$cop, $opc, $Rt, $Rt2, $CRm", [/* For disassembly only; pattern left blank */]> { let Inst{31-28} = 0b1111; let Inst{23-20} = 0b0100; + + bits<4> Rt; + bits<4> Rt2; + bits<4> cop; + bits<3> opc1; + bits<4> CRm; + + let Inst{15-12} = Rt; + let Inst{19-16} = Rt2; + let Inst{11-8} = cop; + let Inst{7-5} = opc1; + let Inst{3-0} = CRm; } -def MRRC : ABI<0b1100, (outs), (ins nohash_imm:$cop, i32imm:$opc, - GPR:$Rt, GPR:$Rt2, nohash_imm:$CRm), - NoItinerary, "mrrc", "\tp$cop, $opc, $Rt, $Rt2, cr$CRm", +def MRRC : ABI<0b1100, (outs), (ins p_imm:$cop, i32imm:$opc, + GPR:$Rt, GPR:$Rt2, c_imm:$CRm), + NoItinerary, "mrrc", "\t$cop, $opc, $Rt, $Rt2, $CRm", [/* For disassembly only; pattern left blank */]> { let Inst{23-20} = 0b0101; + + bits<4> Rt; + bits<4> Rt2; + bits<4> cop; + bits<3> opc1; + bits<4> CRm; + + let Inst{15-12} = Rt; + let Inst{19-16} = Rt2; + let Inst{11-8} = cop; + let Inst{7-5} = opc1; + let Inst{3-0} = CRm; } -def MRRC2 : ABXI<0b1100, (outs), (ins nohash_imm:$cop, i32imm:$opc, - GPR:$Rt, GPR:$Rt2, nohash_imm:$CRm), - NoItinerary, "mrrc2\tp$cop, $opc, $Rt, $Rt2, cr$CRm", +def MRRC2 : ABXI<0b1100, (outs), (ins p_imm:$cop, i32imm:$opc, + GPR:$Rt, GPR:$Rt2, c_imm:$CRm), + NoItinerary, "mrrc2\t$cop, $opc, $Rt, $Rt2, $CRm", [/* For disassembly only; pattern left blank */]> { let Inst{31-28} = 0b1111; let Inst{23-20} = 0b0101; + + bits<4> Rt; + bits<4> Rt2; + bits<4> cop; + bits<3> opc1; + bits<4> CRm; + + let Inst{15-12} = Rt; + let Inst{19-16} = Rt2; + let Inst{11-8} = cop; + let Inst{7-5} = opc1; + let Inst{3-0} = CRm; } //===----------------------------------------------------------------------===// diff --git a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp index 233599b0e73..d849fa59961 100644 --- a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -52,10 +52,11 @@ class ARMAsmParser : public TargetAsmParser { bool Error(SMLoc L, const Twine &Msg) { return Parser.Error(L, Msg); } int TryParseRegister(); + bool TryParseMCRName(SmallVectorImpl&); bool TryParseRegisterWithWriteBack(SmallVectorImpl &); bool ParseRegisterList(SmallVectorImpl &); bool ParseMemory(SmallVectorImpl &); - bool ParseOperand(SmallVectorImpl &); + bool ParseOperand(SmallVectorImpl &, bool isMCR); bool ParsePrefix(ARMMCExpr::VariantKind &RefKind); const MCExpr *ApplyPrefixToExpr(const MCExpr *E, MCSymbolRefExpr::VariantKind Variant); @@ -527,6 +528,67 @@ TryParseRegisterWithWriteBack(SmallVectorImpl &Operands) { return false; } +static int MatchMCRName(StringRef Name) { + // Use the same layout as the tablegen'erated register name matcher. Ugly, + // but efficient. + switch (Name.size()) { + default: break; + case 2: + if (Name[0] != 'p' && Name[0] != 'c') + return -1; + switch (Name[1]) { + default: return -1; + case '0': return 0; + case '1': return 1; + case '2': return 2; + case '3': return 3; + case '4': return 4; + case '5': return 5; + case '6': return 6; + case '7': return 7; + case '8': return 8; + case '9': return 9; + } + break; + case 3: + if ((Name[0] != 'p' && Name[0] != 'c') || Name[1] != '1') + return -1; + switch (Name[2]) { + default: return -1; + case '0': return 10; + case '1': return 11; + case '2': return 12; + case '3': return 13; + case '4': return 14; + case '5': return 15; + } + break; + } + + llvm_unreachable("Unhandled coprocessor operand string!"); + return -1; +} + +/// TryParseMCRName - Try to parse an MCR/MRC symbolic operand +/// name. The token must be an Identifier when called, and if it is a MCR +/// operand name, the token is eaten and the operand is added to the +/// operand list. +bool ARMAsmParser:: +TryParseMCRName(SmallVectorImpl &Operands) { + SMLoc S = Parser.getTok().getLoc(); + const AsmToken &Tok = Parser.getTok(); + assert(Tok.is(AsmToken::Identifier) && "Token is not an Identifier"); + + int Num = MatchMCRName(Tok.getString()); + if (Num == -1) + return true; + + Parser.Lex(); // Eat identifier token. + Operands.push_back(ARMOperand::CreateImm( + MCConstantExpr::Create(Num, getContext()), S, Parser.getTok().getLoc())); + return false; +} + /// Parse a register list, return it if successful else return null. The first /// token must be a '{' when called. bool ARMAsmParser:: @@ -834,7 +896,8 @@ bool ARMAsmParser::ParseShift(ShiftType &St, const MCExpr *&ShiftAmount, /// Parse a arm instruction operand. For now this parses the operand regardless /// of the mnemonic. -bool ARMAsmParser::ParseOperand(SmallVectorImpl &Operands){ +bool ARMAsmParser::ParseOperand(SmallVectorImpl &Operands, + bool isMCR){ SMLoc S, E; switch (getLexer().getKind()) { default: @@ -843,7 +906,11 @@ bool ARMAsmParser::ParseOperand(SmallVectorImpl &Operands){ case AsmToken::Identifier: if (!TryParseRegisterWithWriteBack(Operands)) return false; - // Fall though for the Identifier case that is not a register + if (isMCR && !TryParseMCRName(Operands)) + return false; + + // Fall though for the Identifier case that is not a register or a + // special name. case AsmToken::Integer: // things like 1f and 2b as a branch targets case AsmToken::Dot: { // . as a branch target // This was not a register so parse other operands that start with an @@ -1120,10 +1187,15 @@ bool ARMAsmParser::ParseInstruction(StringRef Name, SMLoc NameLoc, Operands.push_back(ARMOperand::CreateToken(Head, NameLoc)); } + bool isMCR = (Head == "mcr" || Head == "mcr2" || + Head == "mcrr" || Head == "mcrr2" || + Head == "mrc" || Head == "mrc2" || + Head == "mrrc" || Head == "mrrc2"); + // Read the remaining operands. if (getLexer().isNot(AsmToken::EndOfStatement)) { // Read the first operand. - if (ParseOperand(Operands)) { + if (ParseOperand(Operands, isMCR)) { Parser.EatToEndOfStatement(); return true; } @@ -1132,7 +1204,7 @@ bool ARMAsmParser::ParseInstruction(StringRef Name, SMLoc NameLoc, Parser.Lex(); // Eat the comma. // Parse and remember the operand. - if (ParseOperand(Operands)) { + if (ParseOperand(Operands, isMCR)) { Parser.EatToEndOfStatement(); return true; } diff --git a/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp b/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp index 00160da4465..820c2e6ca6f 100644 --- a/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp +++ b/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp @@ -453,6 +453,16 @@ void ARMInstPrinter::printNoHashImmediate(const MCInst *MI, unsigned OpNum, O << MI->getOperand(OpNum).getImm(); } +void ARMInstPrinter::printPImmediate(const MCInst *MI, unsigned OpNum, + raw_ostream &O) { + O << "p" << MI->getOperand(OpNum).getImm(); +} + +void ARMInstPrinter::printCImmediate(const MCInst *MI, unsigned OpNum, + raw_ostream &O) { + O << "c" << MI->getOperand(OpNum).getImm(); +} + void ARMInstPrinter::printPCLabel(const MCInst *MI, unsigned OpNum, raw_ostream &O) { llvm_unreachable("Unhandled PC-relative pseudo-instruction!"); diff --git a/lib/Target/ARM/InstPrinter/ARMInstPrinter.h b/lib/Target/ARM/InstPrinter/ARMInstPrinter.h index eac539c2d0b..3c94b6eabac 100644 --- a/lib/Target/ARM/InstPrinter/ARMInstPrinter.h +++ b/lib/Target/ARM/InstPrinter/ARMInstPrinter.h @@ -95,6 +95,8 @@ public: raw_ostream &O); void printRegisterList(const MCInst *MI, unsigned OpNum, raw_ostream &O); void printNoHashImmediate(const MCInst *MI, unsigned OpNum, raw_ostream &O); + void printPImmediate(const MCInst *MI, unsigned OpNum, raw_ostream &O); + void printCImmediate(const MCInst *MI, unsigned OpNum, raw_ostream &O); void printVFPf32ImmOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O); void printVFPf64ImmOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O); void printNEONModImmOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O); diff --git a/utils/TableGen/EDEmitter.cpp b/utils/TableGen/EDEmitter.cpp index fe97d7385a0..c4391437474 100644 --- a/utils/TableGen/EDEmitter.cpp +++ b/utils/TableGen/EDEmitter.cpp @@ -568,6 +568,8 @@ static int ARMFlagFromOpName(LiteralConstantEmitter *type, IMM("bf_inv_mask_imm"); IMM("jtblock_operand"); IMM("nohash_imm"); + IMM("p_imm"); + IMM("c_imm"); IMM("cpinst_operand"); IMM("setend_op"); IMM("cps_opt");