llvm.org GIT mirror llvm / 9982d6f
MIR Serialization: Serialize physical register machine operands. This commit introduces functionality that's used to serialize machine operands. Only the physical register operands are serialized by this commit. Reviewers: Duncan P. N. Exon Smith Differential Revision: http://reviews.llvm.org/D10525 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@240425 91177308-0d34-0410-b5e6-96231b3b80d8 Alex Lorenz 5 years ago
8 changed file(s) with 296 addition(s) and 4 deletion(s). Raw diff Collapse all Expand all
6767 return C;
6868 }
6969
70 static Cursor lexPercent(Cursor C, MIToken &Token) {
71 auto Range = C;
72 C.advance(); // Skip '%'
73 while (isIdentifierChar(C.peek()))
74 C.advance();
75 Token = MIToken(MIToken::NamedRegister, Range.upto(C));
76 return C;
77 }
78
79 static MIToken::TokenKind symbolToken(char C) {
80 switch (C) {
81 case ',':
82 return MIToken::comma;
83 case '=':
84 return MIToken::equal;
85 default:
86 return MIToken::Error;
87 }
88 }
89
90 static Cursor lexSymbol(Cursor C, MIToken::TokenKind Kind, MIToken &Token) {
91 auto Range = C;
92 C.advance();
93 Token = MIToken(Kind, Range.upto(C));
94 return C;
95 }
96
7097 StringRef llvm::lexMIToken(
7198 StringRef Source, MIToken &Token,
7299 function_ref ErrorCallback) {
79106 auto Char = C.peek();
80107 if (isalpha(Char) || Char == '_')
81108 return lexIdentifier(C, Token).remaining();
109 if (Char == '%')
110 return lexPercent(C, Token).remaining();
111 MIToken::TokenKind Kind = symbolToken(Char);
112 if (Kind != MIToken::Error)
113 return lexSymbol(C, Kind, Token).remaining();
82114 Token = MIToken(MIToken::Error, C.remaining());
83115 ErrorCallback(C.location(),
84116 Twine("unexpected character '") + Twine(Char) + "'");
2929 Eof,
3030 Error,
3131
32 // Tokens with no info.
33 comma,
34 equal,
35
3236 // Identifier tokens
33 Identifier
37 Identifier,
38 NamedRegister
3439 };
3540
3641 private:
4348 TokenKind kind() const { return Kind; }
4449
4550 bool isError() const { return Kind == Error; }
51
52 bool isRegister() const { return Kind == NamedRegister; }
4653
4754 bool is(TokenKind K) const { return Kind == K; }
4855
3333 MIToken Token;
3434 /// Maps from instruction names to op codes.
3535 StringMap Names2InstrOpCodes;
36 /// Maps from register names to registers.
37 StringMap Names2Regs;
3638
3739 public:
3840 MIParser(SourceMgr &SM, MachineFunction &MF, SMDiagnostic &Error,
5254
5355 MachineInstr *parse();
5456
57 bool parseRegister(unsigned &Reg);
58 bool parseRegisterOperand(MachineOperand &Dest, bool IsDef = false);
59 bool parseMachineOperand(MachineOperand &Dest);
60
5561 private:
5662 void initNames2InstrOpCodes();
5763
6066 bool parseInstrName(StringRef InstrName, unsigned &OpCode);
6167
6268 bool parseInstruction(unsigned &OpCode);
69
70 void initNames2Regs();
71
72 /// Try to convert a register name to a register number. Return true if the
73 /// register name is invalid.
74 bool getRegisterByName(StringRef RegName, unsigned &Reg);
6375 };
6476
6577 } // end anonymous namespace
91103 MachineInstr *MIParser::parse() {
92104 lex();
93105
106 // Parse any register operands before '='
107 // TODO: Allow parsing of multiple operands before '='
108 MachineOperand MO = MachineOperand::CreateImm(0);
109 SmallVector Operands;
110 if (Token.isRegister()) {
111 if (parseRegisterOperand(MO, /*IsDef=*/true))
112 return nullptr;
113 Operands.push_back(MO);
114 if (Token.isNot(MIToken::equal)) {
115 error("expected '='");
116 return nullptr;
117 }
118 lex();
119 }
120
94121 unsigned OpCode;
95122 if (Token.isError() || parseInstruction(OpCode))
96123 return nullptr;
97124
98 // TODO: Parse the rest of instruction - machine operands, etc.
125 // TODO: Parse the instruction flags and memory operands.
126
127 // Parse the remaining machine operands.
128 while (Token.isNot(MIToken::Eof)) {
129 if (parseMachineOperand(MO))
130 return nullptr;
131 Operands.push_back(MO);
132 if (Token.is(MIToken::Eof))
133 break;
134 if (Token.isNot(MIToken::comma)) {
135 error("expected ',' before the next machine operand");
136 return nullptr;
137 }
138 lex();
139 }
140
99141 const auto &MCID = MF.getSubtarget().getInstrInfo()->get(OpCode);
100 auto *MI = MF.CreateMachineInstr(MCID, DebugLoc());
142
143 // Verify machine operands.
144 if (!MCID.isVariadic()) {
145 for (size_t I = 0, E = Operands.size(); I < E; ++I) {
146 if (I < MCID.getNumOperands())
147 continue;
148 // Mark this register as implicit to prevent an assertion when it's added
149 // to an instruction. This is a temporary workaround until the implicit
150 // register flag can be parsed.
151 Operands[I].setImplicit();
152 }
153 }
154
155 // TODO: Determine the implicit behaviour when implicit register flags are
156 // parsed.
157 auto *MI = MF.CreateMachineInstr(MCID, DebugLoc(), /*NoImplicit=*/true);
158 for (const auto &Operand : Operands)
159 MI->addOperand(MF, Operand);
101160 return MI;
102161 }
103162
107166 StringRef InstrName = Token.stringValue();
108167 if (parseInstrName(InstrName, OpCode))
109168 return error(Twine("unknown machine instruction name '") + InstrName + "'");
169 lex();
170 return false;
171 }
172
173 bool MIParser::parseRegister(unsigned &Reg) {
174 switch (Token.kind()) {
175 case MIToken::NamedRegister: {
176 StringRef Name = Token.stringValue().drop_front(1); // Drop the '%'
177 if (getRegisterByName(Name, Reg))
178 return error(Twine("unknown register name '") + Name + "'");
179 break;
180 }
181 // TODO: Parse other register kinds.
182 default:
183 llvm_unreachable("The current token should be a register");
184 }
185 return false;
186 }
187
188 bool MIParser::parseRegisterOperand(MachineOperand &Dest, bool IsDef) {
189 unsigned Reg;
190 // TODO: Parse register flags.
191 if (parseRegister(Reg))
192 return true;
193 lex();
194 // TODO: Parse subregister.
195 Dest = MachineOperand::CreateReg(Reg, IsDef);
196 return false;
197 }
198
199 bool MIParser::parseMachineOperand(MachineOperand &Dest) {
200 switch (Token.kind()) {
201 case MIToken::NamedRegister:
202 return parseRegisterOperand(Dest);
203 case MIToken::Error:
204 return true;
205 default:
206 // TODO: parse the other machine operands.
207 return error("expected a machine operand");
208 }
110209 return false;
111210 }
112211
128227 return false;
129228 }
130229
230 void MIParser::initNames2Regs() {
231 if (!Names2Regs.empty())
232 return;
233 const auto *TRI = MF.getSubtarget().getRegisterInfo();
234 assert(TRI && "Expected target register info");
235 for (unsigned I = 0, E = TRI->getNumRegs(); I < E; ++I) {
236 bool WasInserted =
237 Names2Regs.insert(std::make_pair(StringRef(TRI->getName(I)).lower(), I))
238 .second;
239 (void)WasInserted;
240 assert(WasInserted && "Expected registers to be unique case-insensitively");
241 }
242 }
243
244 bool MIParser::getRegisterByName(StringRef RegName, unsigned &Reg) {
245 initNames2Regs();
246 auto RegInfo = Names2Regs.find(RegName);
247 if (RegInfo == Names2Regs.end())
248 return true;
249 Reg = RegInfo->getValue();
250 return false;
251 }
252
131253 MachineInstr *llvm::parseMachineInstr(SourceMgr &SM, MachineFunction &MF,
132254 StringRef Src, SMDiagnostic &Error) {
133255 return MIParser(SM, MF, Error, Src).parse();
4949 MIPrinter(raw_ostream &OS) : OS(OS) {}
5050
5151 void print(const MachineInstr &MI);
52 void print(const MachineOperand &Op, const TargetRegisterInfo *TRI);
5253 };
5354
5455 } // end anonymous namespace
109110
110111 void MIPrinter::print(const MachineInstr &MI) {
111112 const auto &SubTarget = MI.getParent()->getParent()->getSubtarget();
113 const auto *TRI = SubTarget.getRegisterInfo();
114 assert(TRI && "Expected target register info");
112115 const auto *TII = SubTarget.getInstrInfo();
113116 assert(TII && "Expected target instruction info");
114117
118 unsigned I = 0, E = MI.getNumOperands();
119 for (; I < E && MI.getOperand(I).isReg() && MI.getOperand(I).isDef() &&
120 !MI.getOperand(I).isImplicit();
121 ++I) {
122 if (I)
123 OS << ", ";
124 print(MI.getOperand(I), TRI);
125 }
126
127 if (I)
128 OS << " = ";
115129 OS << TII->getName(MI.getOpcode());
116 // TODO: Print the instruction flags, machine operands, machine mem operands.
130 // TODO: Print the instruction flags, machine mem operands.
131 if (I < E)
132 OS << ' ';
133
134 bool NeedComma = false;
135 for (; I < E; ++I) {
136 if (NeedComma)
137 OS << ", ";
138 print(MI.getOperand(I), TRI);
139 NeedComma = true;
140 }
141 }
142
143 static void printReg(unsigned Reg, raw_ostream &OS,
144 const TargetRegisterInfo *TRI) {
145 // TODO: Print Stack Slots.
146 // TODO: Print no register.
147 // TODO: Print virtual registers.
148 if (Reg < TRI->getNumRegs())
149 OS << '%' << StringRef(TRI->getName(Reg)).lower();
150 else
151 llvm_unreachable("Can't print this kind of register yet");
152 }
153
154 void MIPrinter::print(const MachineOperand &Op, const TargetRegisterInfo *TRI) {
155 switch (Op.getType()) {
156 case MachineOperand::MO_Register:
157 // TODO: Print register flags.
158 printReg(Op.getReg(), OS, TRI);
159 // TODO: Print sub register.
160 break;
161 default:
162 // TODO: Print the other machine operands.
163 llvm_unreachable("Can't print this machine operand at the moment");
164 }
117165 }
118166
119167 void llvm::printMIR(raw_ostream &OS, const Module &M) {
0 # RUN: not llc -march=x86-64 -start-after branch-folder -stop-after branch-folder -o /dev/null %s 2>&1 | FileCheck %s
1
2 --- |
3
4 define i32 @foo() {
5 entry:
6 ret i32 0
7 }
8
9 ...
10 ---
11 name: foo
12 body:
13 - name: entry
14 instructions:
15 # CHECK: 1:16: expected a machine operand
16 - '%eax = XOR32rr ='
17 - 'RETQ %eax'
18 ...
19
0 # RUN: not llc -march=x86-64 -start-after branch-folder -stop-after branch-folder -o /dev/null %s 2>&1 | FileCheck %s
1
2 --- |
3
4 define i32 @foo() {
5 entry:
6 ret i32 0
7 }
8
9 ...
10 ---
11 name: foo
12 body:
13 - name: entry
14 instructions:
15 # CHECK: 1:21: expected ',' before the next machine operand
16 - '%eax = XOR32rr %eax %eflags'
17 - 'RETQ %eax'
18 ...
19
0 # RUN: llc -march=x86-64 -start-after branch-folder -stop-after branch-folder -o /dev/null %s | FileCheck %s
1 # This test ensures that the MIR parser parses X86 registers correctly.
2
3 --- |
4
5 define i32 @foo() {
6 entry:
7 ret i32 0
8 }
9
10 ...
11 ---
12 # CHECK: name: foo
13 name: foo
14 body:
15 - name: entry
16 instructions:
17 # CHECK: - '%eax = MOV32r0
18 # CHECK-NEXT: - 'RETQ %eax
19 - '%eax = MOV32r0'
20 - 'RETQ %eax'
21 ...
0 # RUN: not llc -march=x86-64 -start-after branch-folder -stop-after branch-folder -o /dev/null %s 2>&1 | FileCheck %s
1 # This test ensures that an error is reported when an unknown register is
2 # encountered.
3
4 --- |
5
6 define i32 @foo() {
7 entry:
8 ret i32 0
9 }
10
11 ...
12 ---
13 name: foo
14 body:
15 - name: entry
16 instructions:
17 # CHECK: 1:1: unknown register name 'xax'
18 - '%xax = MOV32r0'
19 - 'RETQ %xax'
20 ...