llvm.org GIT mirror llvm / d0ef9f3
MIR Parser: Verify the implicit machine register operands. This commit verifies that the parsed machine instructions contain the implicit register operands as specified by the MCInstrDesc. Variadic and call instructions aren't verified. Reviewers: Duncan P. N. Exon Smith Differential Revision: http://reviews.llvm.org/D10781 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@241537 91177308-0d34-0410-b5e6-96231b3b80d8 Alex Lorenz 5 years ago
13 changed file(s) with 230 addition(s) and 31 deletion(s). Raw diff Collapse all Expand all
2727 using namespace llvm;
2828
2929 namespace {
30
31 /// A wrapper struct around the 'MachineOperand' struct that includes a source
32 /// range.
33 struct MachineOperandWithLocation {
34 MachineOperand Operand;
35 StringRef::iterator Begin;
36 StringRef::iterator End;
37
38 MachineOperandWithLocation(const MachineOperand &Operand,
39 StringRef::iterator Begin, StringRef::iterator End)
40 : Operand(Operand), Begin(Begin), End(End) {}
41 };
3042
3143 class MIParser {
3244 SourceMgr &SM;
89101
90102 bool parseInstruction(unsigned &OpCode);
91103
104 bool verifyImplicitOperands(ArrayRef Operands,
105 const MCInstrDesc &MCID);
106
92107 void initNames2Regs();
93108
94109 /// Try to convert a register name to a register number. Return true if the
138153 // Parse any register operands before '='
139154 // TODO: Allow parsing of multiple operands before '='
140155 MachineOperand MO = MachineOperand::CreateImm(0);
141 SmallVector, 8> Operands;
156 SmallVectorWithLocation, 8> Operands;
142157 if (Token.isRegister() || Token.isRegisterFlag()) {
158 auto Loc = Token.location();
143159 if (parseRegisterOperand(MO, /*IsDef=*/true))
144160 return true;
145 Operands.push_back(MO);
161 Operands.push_back(MachineOperandWithLocation(MO, Loc, Token.location()));
146162 if (Token.isNot(MIToken::equal))
147163 return error("expected '='");
148164 lex();
156172
157173 // Parse the remaining machine operands.
158174 while (Token.isNot(MIToken::Eof)) {
175 auto Loc = Token.location();
159176 if (parseMachineOperand(MO))
160177 return true;
161 Operands.push_back(MO);
178 Operands.push_back(MachineOperandWithLocation(MO, Loc, Token.location()));
162179 if (Token.is(MIToken::Eof))
163180 break;
164181 if (Token.isNot(MIToken::comma))
167184 }
168185
169186 const auto &MCID = MF.getSubtarget().getInstrInfo()->get(OpCode);
187 if (!MCID.isVariadic()) {
188 // FIXME: Move the implicit operand verification to the machine verifier.
189 if (verifyImplicitOperands(Operands, MCID))
190 return true;
191 }
170192
171193 // TODO: Check for extraneous machine operands.
172 // TODO: Check that this instruction has the implicit register operands.
173194 MI = MF.CreateMachineInstr(MCID, DebugLoc(), /*NoImplicit=*/true);
174195 for (const auto &Operand : Operands)
175 MI->addOperand(MF, Operand);
196 MI->addOperand(MF, Operand.Operand);
176197 return false;
177198 }
178199
186207 if (Token.isNot(MIToken::Eof))
187208 return error(
188209 "expected end of string after the machine basic block reference");
210 return false;
211 }
212
213 static const char *printImplicitRegisterFlag(const MachineOperand &MO) {
214 assert(MO.isImplicit());
215 return MO.isDef() ? "implicit-def" : "implicit";
216 }
217
218 static std::string getRegisterName(const TargetRegisterInfo *TRI,
219 unsigned Reg) {
220 assert(TargetRegisterInfo::isPhysicalRegister(Reg) && "expected phys reg");
221 return StringRef(TRI->getName(Reg)).lower();
222 }
223
224 bool MIParser::verifyImplicitOperands(
225 ArrayRef Operands, const MCInstrDesc &MCID) {
226 if (MCID.isCall())
227 // We can't verify call instructions as they can contain arbitrary implicit
228 // register and register mask operands.
229 return false;
230
231 // Gather all the expected implicit operands.
232 SmallVector ImplicitOperands;
233 if (MCID.ImplicitDefs)
234 for (const uint16_t *ImpDefs = MCID.getImplicitDefs(); *ImpDefs; ++ImpDefs)
235 ImplicitOperands.push_back(
236 MachineOperand::CreateReg(*ImpDefs, true, true));
237 if (MCID.ImplicitUses)
238 for (const uint16_t *ImpUses = MCID.getImplicitUses(); *ImpUses; ++ImpUses)
239 ImplicitOperands.push_back(
240 MachineOperand::CreateReg(*ImpUses, false, true));
241
242 const auto *TRI = MF.getSubtarget().getRegisterInfo();
243 assert(TRI && "Expected target register info");
244 size_t I = ImplicitOperands.size(), J = Operands.size();
245 while (I) {
246 --I;
247 if (J) {
248 --J;
249 const auto &ImplicitOperand = ImplicitOperands[I];
250 const auto &Operand = Operands[J].Operand;
251 if (ImplicitOperand.isIdenticalTo(Operand))
252 continue;
253 if (Operand.isReg() && Operand.isImplicit()) {
254 return error(Operands[J].Begin,
255 Twine("expected an implicit register operand '") +
256 printImplicitRegisterFlag(ImplicitOperand) + " %" +
257 getRegisterName(TRI, ImplicitOperand.getReg()) + "'");
258 }
259 }
260 // TODO: Fix source location when Operands[J].end is right before '=', i.e:
261 // insead of reporting an error at this location:
262 // %eax = MOV32r0
263 // ^
264 // report the error at the following location:
265 // %eax = MOV32r0
266 // ^
267 return error(J < Operands.size() ? Operands[J].End : Token.location(),
268 Twine("missing implicit register operand '") +
269 printImplicitRegisterFlag(ImplicitOperands[I]) + " %" +
270 getRegisterName(TRI, ImplicitOperands[I].getReg()) + "'");
271 }
189272 return false;
190273 }
191274
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(i32* %p) {
5 entry:
6 %a = load i32, i32* %p
7 %0 = icmp sle i32 %a, 10
8 br i1 %0, label %less, label %exit
9
10 less:
11 ret i32 0
12
13 exit:
14 ret i32 %a
15 }
16
17
18 ...
19 ---
20 name: foo
21 body:
22 - id: 0
23 name: entry
24 instructions:
25 - '%eax = MOV32rm %rdi, 1, _, 0, _'
26 - 'CMP32ri8 %eax, 10, implicit-def %eflags'
27 # CHECK: [[@LINE+1]]:26: expected an implicit register operand 'implicit %eflags'
28 - 'JG_1 %bb.2.exit, implicit %eax'
29 - id: 1
30 name: less
31 instructions:
32 - '%eax = MOV32r0 implicit-def %eflags'
33 - id: 2
34 name: exit
35 instructions:
36 - 'RETQ %eax'
37 ...
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(i32* %p) {
5 entry:
6 %a = load i32, i32* %p
7 %0 = icmp sle i32 %a, 10
8 br i1 %0, label %less, label %exit
9
10 less:
11 ret i32 0
12
13 exit:
14 ret i32 %a
15 }
16
17
18 ...
19 ---
20 name: foo
21 body:
22 - id: 0
23 name: entry
24 instructions:
25 - '%eax = MOV32rm %rdi, 1, _, 0, _'
26 - 'CMP32ri8 %eax, 10, implicit-def %eflags'
27 # CHECK: [[@LINE+1]]:26: expected an implicit register operand 'implicit %eflags'
28 - 'JG_1 %bb.2.exit, implicit-def %eflags'
29 - id: 1
30 name: less
31 instructions:
32 - '%eax = MOV32r0 implicit-def %eflags'
33 - id: 2
34 name: exit
35 instructions:
36 - 'RETQ %eax'
37 ...
2222 name: entry
2323 instructions:
2424 - '%eax = MOV32rm %rdi, 1, _, 0, _'
25 - 'CMP32ri8 %eax, 10'
25 - 'CMP32ri8 %eax, 10, implicit-def %eflags'
2626 # CHECK: [[@LINE+1]]:18: expected a number after '%bb.'
27 - 'JG_1 %bb.nah'
27 - 'JG_1 %bb.nah, implicit %eflags'
2828 - id: 1
2929 name: yes
3030 instructions:
31 - '%eax = MOV32r0'
31 - '%eax = MOV32r0 implicit-def %eflags'
3232 - id: 2
3333 name: nah
3434 instructions:
3030 # CHECK: - '%rax = MOV64rm %rip, 1, _, @G, _'
3131 - '%rax = MOV64rm %rip, 1, _, @G, _'
3232 - '%eax = MOV32rm %rax, 1, _, 0, _'
33 - '%eax = INC32r %eax'
33 - '%eax = INC32r %eax, implicit-def %eflags'
3434 - 'RETQ %eax'
3535 ...
3636 ---
4343 # CHECK: - '%rax = MOV64rm %rip, 1, _, @0, _'
4444 - '%rax = MOV64rm %rip, 1, _, @0, _'
4545 - '%eax = MOV32rm %rax, 1, _, 0, _'
46 - '%eax = INC32r %eax'
46 - '%eax = INC32r %eax, implicit-def %eflags'
4747 - 'RETQ %eax'
4848 ...
2222 name: entry
2323 instructions:
2424 - '%eax = MOV32rm %rdi, 1, _, 0, _'
25 - 'CMP32ri8 %eax, 10'
25 - 'CMP32ri8 %eax, 10, implicit-def %eflags'
2626 # CHECK: [[@LINE+1]]:14: expected 32-bit integer (too large)
27 - 'JG_1 %bb.123456789123456'
27 - 'JG_1 %bb.123456789123456, implicit %eflags'
2828 - id: 1
2929 instructions:
30 - '%eax = MOV32r0'
30 - '%eax = MOV32r0 implicit-def %eflags'
3131 - id: 2
3232 instructions:
3333 - 'RETQ %eax'
4040 - '%eax = MOV32rm %rdi, 1, _, 0, _'
4141 # CHECK: - 'CMP32ri8 %eax, 10
4242 # CHECK-NEXT: - 'JG_1 %bb.2.exit
43 - 'CMP32ri8 %eax, 10'
44 - 'JG_1 %bb.2.exit'
43 - 'CMP32ri8 %eax, 10, implicit-def %eflags'
44 - 'JG_1 %bb.2.exit, implicit %eflags'
4545 # CHECK: name: less
4646 - id: 1
4747 name: less
4848 instructions:
49 - '%eax = MOV32r0'
49 - '%eax = MOV32r0 implicit-def %eflags'
5050 - id: 2
5151 name: exit
5252 instructions:
6363 - '%eax = MOV32rm %rdi, 1, _, 0, _'
6464 # CHECK: - 'CMP32ri8 %eax, 10
6565 # CHECK-NEXT: - 'JG_1 %bb.2
66 - 'CMP32ri8 %eax, 10'
67 - 'JG_1 %bb.3'
66 - 'CMP32ri8 %eax, 10, implicit-def %eflags'
67 - 'JG_1 %bb.3, implicit %eflags'
6868 - id: 1
6969 instructions:
70 - '%eax = MOV32r0'
70 - '%eax = MOV32r0 implicit-def %eflags'
7171 - id: 3
7272 instructions:
7373 - 'RETQ %eax'
1717 - id: 0
1818 name: entry
1919 instructions:
20 # CHECK: - IMUL32rri8
20 # CHECK: - MOV32rr
2121 # CHECK-NEXT: - RETQ
22 - IMUL32rri8
22 - MOV32rr
2323 - ' RETQ '
2424 ...
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 the MIR parser reports an error when an instruction
2 # is missing one of its implicit register operands.
3
4 --- |
5
6 define i32 @foo(i32* %p) {
7 entry:
8 %a = load i32, i32* %p
9 %0 = icmp sle i32 %a, 10
10 br i1 %0, label %less, label %exit
11
12 less:
13 ret i32 0
14
15 exit:
16 ret i32 %a
17 }
18
19
20 ...
21 ---
22 name: foo
23 body:
24 - id: 0
25 name: entry
26 instructions:
27 - '%eax = MOV32rm %rdi, 1, _, 0, _'
28 - 'CMP32ri8 %eax, 10, implicit-def %eflags'
29 # CHECK: [[@LINE+1]]:24: missing implicit register operand 'implicit %eflags'
30 - 'JG_1 %bb.2.exit'
31 - id: 1
32 name: less
33 instructions:
34 - '%eax = MOV32r0 implicit-def %eflags'
35 - id: 2
36 name: exit
37 instructions:
38 - 'RETQ %eax'
39 ...
1717 instructions:
1818 # CHECK: - '%eax = MOV32r0
1919 # CHECK-NEXT: - 'RETQ %eax
20 - '%eax = MOV32r0'
20 - '%eax = MOV32r0 implicit-def %eflags'
2121 - 'RETQ %eax'
2222 ...
2323 - id: 0
2424 name: body
2525 instructions:
26 - '%eax = IMUL32rri8 %edi, 11'
26 - '%eax = IMUL32rri8 %edi, 11, implicit-def %eflags'
2727 - 'RETQ %eax'
2828 ...
2929 ---
3535 instructions:
3636 # CHECK: - 'PUSH64r %rax
3737 # CHECK-NEXT: - 'CALL64pcrel32 @compute, csr_64, implicit %rsp, implicit %edi, implicit-def %rsp, implicit-def %eax'
38 - 'PUSH64r %rax'
38 - 'PUSH64r %rax, implicit-def %rsp, implicit %rsp'
3939 - 'CALL64pcrel32 @compute, csr_64, implicit %rsp, implicit %edi, implicit-def %rsp, implicit-def %eax'
40 - '%rdx = POP64r'
40 - '%rdx = POP64r implicit-def %rsp, implicit %rsp'
4141 - 'RETQ %eax'
4242 ...
2525 name: entry
2626 instructions:
2727 - '%eax = MOV32rm %rdi, 1, _, 0, _'
28 - 'CMP32ri8 %eax, 10'
28 - 'CMP32ri8 %eax, 10, implicit-def %eflags'
2929 # CHECK: [[@LINE+1]]:14: use of undefined machine basic block #4
30 - 'JG_1 %bb.4'
30 - 'JG_1 %bb.4, implicit %eflags'
3131 - id: 1
3232 instructions:
33 - '%eax = MOV32r0'
33 - '%eax = MOV32r0 implicit-def %eflags'
3434 - id: 2
3535 instructions:
3636 - 'RETQ %eax'
2424 name: entry
2525 instructions:
2626 - '%eax = MOV32rm %rdi, 1, _, 0, _'
27 - 'CMP32ri8 %eax, 10'
27 - 'CMP32ri8 %eax, 10, implicit-def %eflags'
2828 # CHECK: [[@LINE+1]]:14: the name of machine basic block #2 isn't 'hit'
29 - 'JG_1 %bb.2.hit'
29 - 'JG_1 %bb.2.hit, implicit %eflags'
3030 - id: 1
3131 name: less
3232 instructions:
33 - '%eax = MOV32r0'
33 - '%eax = MOV32r0 implicit-def %eflags'
3434 - id: 2
3535 name: exit
3636 instructions: