Skip to content

Commit bbad419

Browse files
committedOct 10, 2017
[ARM, Asm] Add diagnostics for general-purpose register operands
This adds diagnostic strings for the ARM general-purpose register classes, which will be used when these classes are expected by the assembler, but the provided operand is not valid. One of these, rGPR, requires C++ code to select the correct error message, as that class contains different registers in pre-v8 and v8 targets. The rest can all have their diagnostic strings stored in the tablegen description of them. Differential revision: https://reviews.llvm.org/D36692 llvm-svn: 315303
1 parent 312b64f commit bbad419

16 files changed

+177
-86
lines changed
 

‎llvm/lib/Target/ARM/ARMRegisterInfo.td

+13-3
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@ def GPR : RegisterClass<"ARM", [i32], 32, (add (sequence "R%u", 0, 12),
213213
let AltOrderSelect = [{
214214
return 1 + MF.getSubtarget<ARMSubtarget>().isThumb1Only();
215215
}];
216+
let DiagnosticString = "operand must be a register in range [r0, r15]";
216217
}
217218

218219
// GPRs without the PC. Some ARM instructions do not allow the PC in
@@ -223,6 +224,7 @@ def GPRnopc : RegisterClass<"ARM", [i32], 32, (sub GPR, PC)> {
223224
let AltOrderSelect = [{
224225
return 1 + MF.getSubtarget<ARMSubtarget>().isThumb1Only();
225226
}];
227+
let DiagnosticString = "operand must be a register in range [r0, r14]";
226228
}
227229

228230
// GPRs without the PC but with APSR. Some instructions allow accessing the
@@ -233,14 +235,17 @@ def GPRwithAPSR : RegisterClass<"ARM", [i32], 32, (add (sub GPR, PC), APSR_NZCV)
233235
let AltOrderSelect = [{
234236
return 1 + MF.getSubtarget<ARMSubtarget>().isThumb1Only();
235237
}];
238+
let DiagnosticString = "operand must be a register in range [r0, r14] or apsr_nzcv";
236239
}
237240

238241
// GPRsp - Only the SP is legal. Used by Thumb1 instructions that want the
239242
// implied SP argument list.
240243
// FIXME: It would be better to not use this at all and refactor the
241244
// instructions to not have SP an an explicit argument. That makes
242245
// frame index resolution a bit trickier, though.
243-
def GPRsp : RegisterClass<"ARM", [i32], 32, (add SP)>;
246+
def GPRsp : RegisterClass<"ARM", [i32], 32, (add SP)> {
247+
let DiagnosticString = "operand must be a register sp";
248+
}
244249

245250
// restricted GPR register class. Many Thumb2 instructions allow the full
246251
// register range for operands, but have undefined behaviours when PC
@@ -251,18 +256,23 @@ def rGPR : RegisterClass<"ARM", [i32], 32, (sub GPR, SP, PC)> {
251256
let AltOrderSelect = [{
252257
return 1 + MF.getSubtarget<ARMSubtarget>().isThumb1Only();
253258
}];
259+
let DiagnosticType = "rGPR";
254260
}
255261

256262
// Thumb registers are R0-R7 normally. Some instructions can still use
257263
// the general GPR register class above (MOV, e.g.)
258-
def tGPR : RegisterClass<"ARM", [i32], 32, (trunc GPR, 8)>;
264+
def tGPR : RegisterClass<"ARM", [i32], 32, (trunc GPR, 8)> {
265+
let DiagnosticString = "operand must be a register in range [r0, r7]";
266+
}
259267

260268
// Thumb registers R0-R7 and the PC. Some instructions like TBB or THH allow
261269
// the PC to be used as a destination operand as well.
262270
def tGPRwithpc : RegisterClass<"ARM", [i32], 32, (add tGPR, PC)>;
263271

264272
// The high registers in thumb mode, R8-R15.
265-
def hGPR : RegisterClass<"ARM", [i32], 32, (sub GPR, tGPR)>;
273+
def hGPR : RegisterClass<"ARM", [i32], 32, (sub GPR, tGPR)> {
274+
let DiagnosticString = "operand must be a register in range [r8, r15]";
275+
}
266276

267277
// For tail calls, we can't use callee-saved registers, as they are restored
268278
// to the saved value before the tail call, which would clobber a call address.

‎llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp

+21-2
Original file line numberDiff line numberDiff line change
@@ -623,6 +623,8 @@ class ARMAsmParser : public MCTargetAsmParser {
623623
SmallString<128> Message;
624624
};
625625

626+
const char *getCustomOperandDiag(ARMMatchResultTy MatchError);
627+
626628
void FilterNearMisses(SmallVectorImpl<NearMissInfo> &NearMissesIn,
627629
SmallVectorImpl<NearMissMessage> &NearMissesOut,
628630
SMLoc IDLoc, OperandVector &Operands);
@@ -10094,6 +10096,23 @@ extern "C" void LLVMInitializeARMAsmParser() {
1009410096
#define GET_MATCHER_IMPLEMENTATION
1009510097
#include "ARMGenAsmMatcher.inc"
1009610098

10099+
// Some diagnostics need to vary with subtarget features, so they are handled
10100+
// here. For example, the DPR class has either 16 or 32 registers, depending
10101+
// on the FPU available.
10102+
const char *
10103+
ARMAsmParser::getCustomOperandDiag(ARMMatchResultTy MatchError) {
10104+
switch (MatchError) {
10105+
// rGPR contains sp starting with ARMv8.
10106+
case Match_rGPR:
10107+
return hasV8Ops() ? "operand must be a register in range [r0, r14]"
10108+
: "operand must be a register in range [r0, r12] or r14";
10109+
10110+
// For all other diags, use the static string from tablegen.
10111+
default:
10112+
return getMatchKindDiag(MatchError);
10113+
}
10114+
}
10115+
1009710116
// Process the list of near-misses, throwing away ones we don't want to report
1009810117
// to the user, and converting the rest to a source location and string that
1009910118
// should be reported.
@@ -10124,7 +10143,7 @@ ARMAsmParser::FilterNearMisses(SmallVectorImpl<NearMissInfo> &NearMissesIn,
1012410143
SMLoc OperandLoc =
1012510144
((ARMOperand &)*Operands[I.getOperandIndex()]).getStartLoc();
1012610145
const char *OperandDiag =
10127-
getMatchKindDiag((ARMMatchResultTy)I.getOperandError());
10146+
getCustomOperandDiag((ARMMatchResultTy)I.getOperandError());
1012810147

1012910148
// If we have already emitted a message for a superclass, don't also report
1013010149
// the sub-class. We consider all operand classes that we don't have a
@@ -10382,7 +10401,7 @@ unsigned ARMAsmParser::validateTargetOperandClass(MCParsedAsmOperand &AsmOp,
1038210401
case MCK_rGPR:
1038310402
if (hasV8Ops() && Op.isReg() && Op.getReg() == ARM::SP)
1038410403
return Match_Success;
10385-
break;
10404+
return Match_rGPR;
1038610405
case MCK_GPRPair:
1038710406
if (Op.isReg() &&
1038810407
MRI->getRegClass(ARM::GPRRegClassID).contains(Op.getReg()))

‎llvm/test/MC/ARM/basic-thumb2-instructions-v8.s

+11-5
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,18 @@
3232
@ CHECK-V8: and.w r6, r3, sp, asr #16 @ encoding: [0x03,0xea,0x2d,0x46]
3333
@ CHECK-V8: and sp, r0, #0 @ encoding: [0x00,0xf0,0x00,0x0d]
3434
@ CHECK-V7: error: invalid instruction, any one of the following would fix this:
35-
@ CHECk-V7: note: instruction variant requires ARMv8 or later
36-
@ CHECk-V7: note: invalid operand for instruction
35+
@ CHECK-V7-NEXT: sbc.w r6, r3, sp, asr #16
36+
@ CHECK-V7: note: instruction variant requires ARMv8 or later
37+
@ CHECK-V7: note: operand must be a register in range [r0, r12] or r14
3738
@ CHECK-V7: error: invalid instruction, any one of the following would fix this:
38-
@ CHECk-V7: note: instruction variant requires ARMv8 or later
39-
@ CHECk-V7: note: invalid operand for instruction
40-
@ CHECK-V7: error: invalid operand for instruction
39+
@ CHECK-V7-NEXT: and.w r6, r3, sp, asr #16
40+
@ CHECK-V7: note: invalid operand for instruction
41+
@ CHECK-V7: note: instruction variant requires ARMv8 or later
42+
@ CHECK-V7: note: operand must be a register in range [r0, r12] or r14
43+
@ CHECK-V7: error: invalid instruction, any one of the following would fix this:
44+
@ CHECK-V7-NEXT: and sp, r0, #0
45+
@ CHECK-V7: note: operand must be a register in range [r0, r12] or r14
46+
@ CHECK-V7: note: invalid operand for instruction
4147

4248
@ DCPS{1,2,3} (in ARMv8 only)
4349
dcps1

‎llvm/test/MC/ARM/diagnostics.s

+10-6
Original file line numberDiff line numberDiff line change
@@ -182,8 +182,12 @@
182182
@ Invalid 's' bit usage for MOVW
183183
movs r6, #0xffff
184184
movwseq r9, #0xffff
185-
@ CHECK-ERRORS: error: invalid operand for instruction
185+
@ CHECK-ERRORS: error: invalid instruction, any one of the following would fix this:
186+
@ CHECK-ERRORS-NEXT: movs r6, #0xffff
187+
@ CHECK-ERRORS: note: invalid operand for instruction
188+
@ CHECK-ERRORS: note: operand must be a register in range [r0, r15]
186189
@ CHECK-ERRORS: error: instruction 'movw' can not set flags, but 's' suffix specified
190+
@ CHECK-ERRORS-NEXT: movwseq r9, #0xffff
187191

188192
@ Out of range immediate for MOVT
189193
movt r9, 0x10000
@@ -359,7 +363,7 @@
359363
@ CHECK-ERRORS: error: 'ror' rotate amount must be 8, 16, or 24
360364
@ CHECK-ERRORS: sxtah r9, r3, r3, ror #-8
361365
@ CHECK-ERRORS: ^
362-
@ CHECK-ERRORS: error: invalid operand for instruction
366+
@ CHECK-ERRORS: error: operand must be a register in range [r0, r14]
363367
@ CHECK-ERRORS: sxtb16ge r2, r3, lsr #24
364368
@ CHECK-ERRORS: ^
365369

@@ -379,16 +383,16 @@
379383
sbfx sp, pc, #4, #5
380384
ubfx pc, r0, #0, #31
381385
ubfx r14, pc, #1, #2
382-
@ CHECK-ERRORS: error: invalid operand for instruction
386+
@ CHECK-ERRORS: error: operand must be a register in range [r0, r14]
383387
@ CHECK-ERRORS: sbfx pc, r2, #1, #3
384388
@ CHECK-ERRORS: ^
385-
@ CHECK-ERRORS: error: invalid operand for instruction
389+
@ CHECK-ERRORS: error: operand must be a register in range [r0, r14]
386390
@ CHECK-ERRORS: sbfx sp, pc, #4, #5
387391
@ CHECK-ERRORS: ^
388-
@ CHECK-ERRORS: error: invalid operand for instruction
392+
@ CHECK-ERRORS: error: operand must be a register in range [r0, r14]
389393
@ CHECK-ERRORS: ubfx pc, r0, #0, #31
390394
@ CHECK-ERRORS: ^
391-
@ CHECK-ERRORS: error: invalid operand for instruction
395+
@ CHECK-ERRORS: error: operand must be a register in range [r0, r14]
392396
@ CHECK-ERRORS: ubfx r14, pc, #1, #2
393397
@ CHECK-ERRORS: ^
394398

Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
@ RUN: not llvm-mc -triple=armv7-linux-gnueabi %s 2>&1 | FileCheck %s
2+
3+
@ FIXME: These errors are inaccurate because the error is being reported on the
4+
@ implicit r13 operand added after r12.
5+
26
.text
37
.thumb
4-
@ CHECK: error: invalid operand for instruction
8+
@ CHECK: error: operand must be a register in range [r0, r12] or r14
59
@ CHECK: ldrd r12, [r0, #512]
610
ldrd r12, [r0, #512]
711

8-
@ CHECK: error: invalid operand for instruction
12+
@ CHECK: error: operand must be a register in range [r0, r12] or r14
913
@ CHECK: strd r12, [r0, #512]
1014
strd r12, [r0, #512]

‎llvm/test/MC/ARM/lsl-zero-errors.s

+42-23
Original file line numberDiff line numberDiff line change
@@ -15,26 +15,26 @@
1515

1616
// CHECK-NONARM: error: invalid instruction, any one of the following would fix this:
1717
// CHECK-NONARM-NEXT: lsl pc, r0, #0
18-
// CHECK-NONARM: instruction requires: arm-mode
19-
// CHECK-NONARM: invalid operand for instruction
18+
// CHECK-NONARM: note: instruction requires: arm-mode
19+
// CHECK-NONARM: note: operand must be a register in range [r0, r14]
2020

2121
// CHECK-NONARM: error: invalid instruction, any one of the following would fix this:
2222
// CHECK-NONARM-NEXT: lsl r0, pc, #0
23-
// CHECK-NONARM: instruction requires: arm-mode
24-
// CHECK-NONARM: invalid operand for instruction
23+
// CHECK-NONARM: note: instruction requires: arm-mode
24+
// CHECK-NONARM: note: operand must be a register in range [r0, r14]
2525

2626
// CHECK-NONARM: error: instruction requires: arm-mode
2727
// CHECK-NONARM-NEXT: lsl pc, pc, #0
2828

2929
// CHECK-NONARM: error: invalid instruction, any one of the following would fix this:
3030
// CHECK-NONARM-NEXT: lsls pc, r0, #0
31-
// CHECK-NONARM: instruction requires: arm-mode
32-
// CHECK-NONARM: invalid operand for instruction
31+
// CHECK-NONARM: note: instruction requires: arm-mode
32+
// CHECK-NONARM: note: operand must be a register in range [r0, r14]
3333

3434
// CHECK-NONARM: error: invalid instruction, any one of the following would fix this:
3535
// CHECK-NONARM-NEXT: lsls r0, pc, #0
36-
// CHECK-NONARM: instruction requires: arm-mode
37-
// CHECK-NONARM: invalid operand for instruction
36+
// CHECK-NONARM: note: instruction requires: arm-mode
37+
// CHECK-NONARM: note: operand must be a register in range [r0, r14]
3838

3939
// CHECK-NONARM: error: instruction requires: arm-mode
4040
// CHECK-NONARM-NEXT: lsls pc, pc, #0
@@ -55,24 +55,35 @@
5555

5656
// CHECK-NONARM: error: invalid instruction, any one of the following would fix this:
5757
// CHECK-NONARM-NEXT: mov pc, r0, lsl #0
58-
// CHECK-NONARM: invalid operand for instruction
59-
// CHECK-NONARM: invalid operand for instruction
58+
// CHECK-NONARM: note: operand must be a register in range [r0, r15]
59+
// CHECK-THUMBV7: note: operand must be a register in range [r0, r12] or r14
60+
// CHECK-THUMBV8: note: operand must be a register in range [r0, r14]
61+
6062
// CHECK-NONARM: error: invalid instruction, any one of the following would fix this:
6163
// CHECK-NONARM-NEXT: mov r0, pc, lsl #0
62-
// CHECK-NONARM: invalid operand for instruction
63-
// CHECK-NONARM: invalid operand for instruction
64-
// CHECK-NONARM: operand must be an immediate in the range [256,65535]
64+
// CHECK-NONARM: note: operand must be a register in range [r0, r15]
65+
// CHECK-NONARM: note: invalid operand for instruction
66+
// CHECK-NONARM: note: invalid operand for instruction
67+
// CHECK-NONARM: note: operand must be an immediate in the range [256,65535]
68+
6569
// CHECK-NONARM: error: invalid instruction, any one of the following would fix this:
6670
// CHECK-NONARM-NEXT: mov pc, pc, lsl #0
67-
// CHECK-NONARM: invalid operand for instruction
68-
// CHECK-NONARM: invalid operand for instruction
69-
// CHECK-NONARM: error: invalid operand for instruction
71+
// CHECK-NONARM: note: operand must be a register in range [r0, r15]
72+
// CHECK-THUMBV7: note: operand must be a register in range [r0, r12] or r14
73+
// CHECK-THUMBV8: note: operand must be a register in range [r0, r14]
74+
75+
// CHECK-THUMBV7: error: operand must be a register in range [r0, r12] or r14
76+
// CHECK-THUMBV8: error: operand must be a register in range [r0, r14]
7077
// CHECK-NONARM-NEXT: movs pc, r0, lsl #0
78+
7179
// CHECK-NONARM: error: invalid instruction, any one of the following would fix this:
7280
// CHECK-NONARM-NEXT: movs r0, pc, lsl #0
73-
// CHECK-NONARM: invalid operand for instruction
74-
// CHECK-NONARM: invalid operand for instruction
75-
// CHECK-NONARM: error: invalid operand for instruction
81+
// CHECK-NONARM: note: operand must be a register in range [r0, r14]
82+
// CHECK-NONARM: note: invalid operand for instruction
83+
// CHECK-NONARM: note: invalid operand for instruction
84+
85+
// CHECK-THUMBV7: error: operand must be a register in range [r0, r12] or r14
86+
// CHECK-THUMBV8: error: operand must be a register in range [r0, r14]
7687
// CHECK-NONARM-NEXT: movs pc, pc, lsl #0
7788

7889
// CHECK-ARM: mov pc, r0 @ encoding: [0x00,0xf0,0xa0,0xe1]
@@ -118,17 +129,25 @@
118129

119130
// FIXME: We should consistently have the "requires ARMv8" error here
120131
// CHECK-THUMBV7: error: invalid instruction, any one of the following would fix this:
121-
// CHECK-THUMBV7: invalid operand for instruction
122132
// CHECK-THUMBV7-NEXT: mov sp, sp, lsl #0
133+
// CHECK-THUMBV7: note: operand must be a register in range [r0, r15]
134+
// CHECK-THUMBV7: note: operand must be a register in range [r0, r12] or r14
135+
123136
// CHECK-THUMBV7: error: invalid instruction, any one of the following would fix this:
124-
// CHECK-THUMBV7: invalid operand for instruction
125137
// CHECK-THUMBV7-NEXT: movs sp, sp, lsl #0
138+
// CHECK-THUMBV7: note: operand must be a register in range [r0, r14]
139+
// CHECK-THUMBV7: note: operand must be a register in range [r0, r12] or r14
140+
126141
// CHECK-THUMBV7: error: invalid instruction, any one of the following would fix this:
127-
// CHECK-THUMBV7: instruction variant requires ARMv8 or later
128142
// CHECK-THUMBV7-NEXT: movs r0, sp, lsl #0
143+
// CHECK-THUMBV7: note: operand must be a register in range [r0, r14]
144+
// CHECK-THUMBV7: note: invalid operand for instruction
145+
// CHECK-THUMBV7: note: instruction variant requires ARMv8 or later
146+
129147
// CHECK-THUMBV7: error: invalid instruction, any one of the following would fix this:
130-
// CHECK-THUMBV7: invalid operand for instruction
131148
// CHECK-THUMBV7-NEXT: movs sp, r0, lsl #0
149+
// CHECK-THUMBV7: note: operand must be a register in range [r0, r14]
150+
// CHECK-THUMBV7: note: operand must be a register in range [r0, r12] or r14
132151

133152
// CHECK-ARM: mov sp, sp @ encoding: [0x0d,0xd0,0xa0,0xe1]
134153
// CHECK-ARM: movs sp, sp @ encoding: [0x0d,0xd0,0xb0,0xe1]

‎llvm/test/MC/ARM/negative-immediates-fail.s

+13-4
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,27 @@
33
.arm
44

55
ADC r0, r1, #0xFFFFFEEE
6-
# CHECK: error: invalid operand for instruction
6+
# CHECK: error: invalid instruction, any one of the following would fix this:
7+
# CHECK: note: invalid operand for instruction
8+
# CHECK: note: operand must be a register in range [r0, r15]
79
ADC r0, r1, #0xABFEABFF
8-
# CHECK: error: invalid operand for instruction
10+
# CHECK: error: invalid instruction, any one of the following would fix this:
11+
# CHECK: note: invalid operand for instruction
12+
# CHECK: note: operand must be a register in range [r0, r15]
913
ADC r0, r1, #0xFFFFFE02
10-
# CHECK: error: invalid operand for instruction
14+
# CHECK: error: invalid instruction, any one of the following would fix this:
15+
# CHECK: note: invalid operand for instruction
16+
# CHECK: note: operand must be a register in range [r0, r15]
1117

1218
ADD.W r0, r0, #0xFF01FF01
13-
# CHECK: invalid operand for instruction
19+
# CHECK: error: invalid instruction, any one of the following would fix this:
20+
# CHECK: note: invalid operand for instruction
21+
# CHECK: note: operand must be a register in range [r0, r15]
1422

1523
ORR r0, r1, #0xFFFFFF00
1624
# CHECK: error: invalid instruction, any one of the following would fix this:
1725
# CHECK: note: invalid operand for instruction
26+
# CHECK: note: operand must be a register in range [r0, r15]
1827
# CHECK: note: instruction requires: thumb2
1928
ORN r0, r1, #0xFFFFFF00
2029
# CHECK: error: instruction requires: thumb2

‎llvm/test/MC/ARM/negative-immediates-thumb1-fail.s

+2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ ADDs r1, r0, #0xFFFFFFF5
77
# CHECK-DAG: note: instruction requires: thumb2
88
# CHECK-DAG: note: invalid operand for instruction
99
# CHECK-DAG: note: operand must be an immediate in the range [0,7]
10+
# CHECK-DAG: note: operand must be a register in range [r0, r7]
1011

1112
ADDs r0, #0xFFFFFEFF
1213
# CHECK: error: invalid instruction, any one of the following would fix this:
@@ -17,6 +18,7 @@ SUBs r1, r0, #0xFFFFFFF5
1718
# CHECK: error: invalid instruction, any one of the following would fix this:
1819
# CHECK-DAG: note: invalid operand for instruction
1920
# CHECK-DAG: note: operand must be an immediate in the range [0,7]
21+
# CHECK-DAG: note: operand must be a register in range [r0, r7]
2022

2123
SUBs r0, #0xFFFFFEFF
2224
# CHECK: error: invalid instruction, any one of the following would fix this:

‎llvm/test/MC/ARM/register-token-source-loc.s

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
add sp, r0, #4
77
// CHECK: error: invalid instruction, any one of the following would fix this:
88
// CHECK: note: instruction requires: thumb2
9-
// CHECK: note: invalid operand for instruction
9+
// CHECK: note: operand must be a register sp
1010
// CHECK-NEXT: {{^ add sp, r0, #4}}
1111
// CHECK-NEXT: {{^ \^}}
1212
// CHECK: note: too many operands for instruction

‎llvm/test/MC/ARM/thumb-branch-errors.s

+4-2
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,7 @@
1818
@ CHECK: cbnz r2, #1
1919
@ CHECK: error: branch target out of range
2020
@ CHECK: beq #1
21-
@ CHECK: error: invalid operand for instruction
22-
@ CHECK: blx #2
21+
@ CHECK: invalid operand for instruction
22+
@ CHECK-NEXT: blx #2
23+
@ CHECK: operand must be a register in range [r0, r15]
24+
@ CHECK-NEXT: blx #2

0 commit comments

Comments
 (0)
Please sign in to comment.