Skip to content

Commit

Permalink
[ARM, Asm] Add diagnostics for general-purpose register operands
Browse files Browse the repository at this point in the history
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
  • Loading branch information
ostannard committed Oct 10, 2017
1 parent 312b64f commit bbad419
Show file tree
Hide file tree
Showing 16 changed files with 177 additions and 86 deletions.
16 changes: 13 additions & 3 deletions llvm/lib/Target/ARM/ARMRegisterInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ def GPR : RegisterClass<"ARM", [i32], 32, (add (sequence "R%u", 0, 12),
let AltOrderSelect = [{
return 1 + MF.getSubtarget<ARMSubtarget>().isThumb1Only();
}];
let DiagnosticString = "operand must be a register in range [r0, r15]";
}

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

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

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

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

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

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

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

// For tail calls, we can't use callee-saved registers, as they are restored
// to the saved value before the tail call, which would clobber a call address.
Expand Down
23 changes: 21 additions & 2 deletions llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -623,6 +623,8 @@ class ARMAsmParser : public MCTargetAsmParser {
SmallString<128> Message;
};

const char *getCustomOperandDiag(ARMMatchResultTy MatchError);

void FilterNearMisses(SmallVectorImpl<NearMissInfo> &NearMissesIn,
SmallVectorImpl<NearMissMessage> &NearMissesOut,
SMLoc IDLoc, OperandVector &Operands);
Expand Down Expand Up @@ -10094,6 +10096,23 @@ extern "C" void LLVMInitializeARMAsmParser() {
#define GET_MATCHER_IMPLEMENTATION
#include "ARMGenAsmMatcher.inc"

// Some diagnostics need to vary with subtarget features, so they are handled
// here. For example, the DPR class has either 16 or 32 registers, depending
// on the FPU available.
const char *
ARMAsmParser::getCustomOperandDiag(ARMMatchResultTy MatchError) {
switch (MatchError) {
// rGPR contains sp starting with ARMv8.
case Match_rGPR:
return hasV8Ops() ? "operand must be a register in range [r0, r14]"
: "operand must be a register in range [r0, r12] or r14";

// For all other diags, use the static string from tablegen.
default:
return getMatchKindDiag(MatchError);
}
}

// Process the list of near-misses, throwing away ones we don't want to report
// to the user, and converting the rest to a source location and string that
// should be reported.
Expand Down Expand Up @@ -10124,7 +10143,7 @@ ARMAsmParser::FilterNearMisses(SmallVectorImpl<NearMissInfo> &NearMissesIn,
SMLoc OperandLoc =
((ARMOperand &)*Operands[I.getOperandIndex()]).getStartLoc();
const char *OperandDiag =
getMatchKindDiag((ARMMatchResultTy)I.getOperandError());
getCustomOperandDiag((ARMMatchResultTy)I.getOperandError());

// If we have already emitted a message for a superclass, don't also report
// the sub-class. We consider all operand classes that we don't have a
Expand Down Expand Up @@ -10382,7 +10401,7 @@ unsigned ARMAsmParser::validateTargetOperandClass(MCParsedAsmOperand &AsmOp,
case MCK_rGPR:
if (hasV8Ops() && Op.isReg() && Op.getReg() == ARM::SP)
return Match_Success;
break;
return Match_rGPR;
case MCK_GPRPair:
if (Op.isReg() &&
MRI->getRegClass(ARM::GPRRegClassID).contains(Op.getReg()))
Expand Down
16 changes: 11 additions & 5 deletions llvm/test/MC/ARM/basic-thumb2-instructions-v8.s
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,18 @@
@ CHECK-V8: and.w r6, r3, sp, asr #16 @ encoding: [0x03,0xea,0x2d,0x46]
@ CHECK-V8: and sp, r0, #0 @ encoding: [0x00,0xf0,0x00,0x0d]
@ CHECK-V7: error: invalid instruction, any one of the following would fix this:
@ CHECk-V7: note: instruction variant requires ARMv8 or later
@ CHECk-V7: note: invalid operand for instruction
@ CHECK-V7-NEXT: sbc.w r6, r3, sp, asr #16
@ CHECK-V7: note: instruction variant requires ARMv8 or later
@ CHECK-V7: note: operand must be a register in range [r0, r12] or r14
@ CHECK-V7: error: invalid instruction, any one of the following would fix this:
@ CHECk-V7: note: instruction variant requires ARMv8 or later
@ CHECk-V7: note: invalid operand for instruction
@ CHECK-V7: error: invalid operand for instruction
@ CHECK-V7-NEXT: and.w r6, r3, sp, asr #16
@ CHECK-V7: note: invalid operand for instruction
@ CHECK-V7: note: instruction variant requires ARMv8 or later
@ CHECK-V7: note: operand must be a register in range [r0, r12] or r14
@ CHECK-V7: error: invalid instruction, any one of the following would fix this:
@ CHECK-V7-NEXT: and sp, r0, #0
@ CHECK-V7: note: operand must be a register in range [r0, r12] or r14
@ CHECK-V7: note: invalid operand for instruction

@ DCPS{1,2,3} (in ARMv8 only)
dcps1
Expand Down
16 changes: 10 additions & 6 deletions llvm/test/MC/ARM/diagnostics.s
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,12 @@
@ Invalid 's' bit usage for MOVW
movs r6, #0xffff
movwseq r9, #0xffff
@ CHECK-ERRORS: error: invalid operand for instruction
@ CHECK-ERRORS: error: invalid instruction, any one of the following would fix this:
@ CHECK-ERRORS-NEXT: movs r6, #0xffff
@ CHECK-ERRORS: note: invalid operand for instruction
@ CHECK-ERRORS: note: operand must be a register in range [r0, r15]
@ CHECK-ERRORS: error: instruction 'movw' can not set flags, but 's' suffix specified
@ CHECK-ERRORS-NEXT: movwseq r9, #0xffff

@ Out of range immediate for MOVT
movt r9, 0x10000
Expand Down Expand Up @@ -359,7 +363,7 @@
@ CHECK-ERRORS: error: 'ror' rotate amount must be 8, 16, or 24
@ CHECK-ERRORS: sxtah r9, r3, r3, ror #-8
@ CHECK-ERRORS: ^
@ CHECK-ERRORS: error: invalid operand for instruction
@ CHECK-ERRORS: error: operand must be a register in range [r0, r14]
@ CHECK-ERRORS: sxtb16ge r2, r3, lsr #24
@ CHECK-ERRORS: ^

Expand All @@ -379,16 +383,16 @@
sbfx sp, pc, #4, #5
ubfx pc, r0, #0, #31
ubfx r14, pc, #1, #2
@ CHECK-ERRORS: error: invalid operand for instruction
@ CHECK-ERRORS: error: operand must be a register in range [r0, r14]
@ CHECK-ERRORS: sbfx pc, r2, #1, #3
@ CHECK-ERRORS: ^
@ CHECK-ERRORS: error: invalid operand for instruction
@ CHECK-ERRORS: error: operand must be a register in range [r0, r14]
@ CHECK-ERRORS: sbfx sp, pc, #4, #5
@ CHECK-ERRORS: ^
@ CHECK-ERRORS: error: invalid operand for instruction
@ CHECK-ERRORS: error: operand must be a register in range [r0, r14]
@ CHECK-ERRORS: ubfx pc, r0, #0, #31
@ CHECK-ERRORS: ^
@ CHECK-ERRORS: error: invalid operand for instruction
@ CHECK-ERRORS: error: operand must be a register in range [r0, r14]
@ CHECK-ERRORS: ubfx r14, pc, #1, #2
@ CHECK-ERRORS: ^

Expand Down
8 changes: 6 additions & 2 deletions llvm/test/MC/ARM/ldrd-strd-gnu-thumb-bad-regs.s
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
@ RUN: not llvm-mc -triple=armv7-linux-gnueabi %s 2>&1 | FileCheck %s

@ FIXME: These errors are inaccurate because the error is being reported on the
@ implicit r13 operand added after r12.

.text
.thumb
@ CHECK: error: invalid operand for instruction
@ CHECK: error: operand must be a register in range [r0, r12] or r14
@ CHECK: ldrd r12, [r0, #512]
ldrd r12, [r0, #512]

@ CHECK: error: invalid operand for instruction
@ CHECK: error: operand must be a register in range [r0, r12] or r14
@ CHECK: strd r12, [r0, #512]
strd r12, [r0, #512]
65 changes: 42 additions & 23 deletions llvm/test/MC/ARM/lsl-zero-errors.s
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,26 @@

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

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

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

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

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

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

// CHECK-NONARM: error: invalid instruction, any one of the following would fix this:
// CHECK-NONARM-NEXT: mov pc, r0, lsl #0
// CHECK-NONARM: invalid operand for instruction
// CHECK-NONARM: invalid operand for instruction
// CHECK-NONARM: note: operand must be a register in range [r0, r15]
// CHECK-THUMBV7: note: operand must be a register in range [r0, r12] or r14
// CHECK-THUMBV8: note: operand must be a register in range [r0, r14]

// CHECK-NONARM: error: invalid instruction, any one of the following would fix this:
// CHECK-NONARM-NEXT: mov r0, pc, lsl #0
// CHECK-NONARM: invalid operand for instruction
// CHECK-NONARM: invalid operand for instruction
// CHECK-NONARM: operand must be an immediate in the range [256,65535]
// CHECK-NONARM: note: operand must be a register in range [r0, r15]
// CHECK-NONARM: note: invalid operand for instruction
// CHECK-NONARM: note: invalid operand for instruction
// CHECK-NONARM: note: operand must be an immediate in the range [256,65535]

// CHECK-NONARM: error: invalid instruction, any one of the following would fix this:
// CHECK-NONARM-NEXT: mov pc, pc, lsl #0
// CHECK-NONARM: invalid operand for instruction
// CHECK-NONARM: invalid operand for instruction
// CHECK-NONARM: error: invalid operand for instruction
// CHECK-NONARM: note: operand must be a register in range [r0, r15]
// CHECK-THUMBV7: note: operand must be a register in range [r0, r12] or r14
// CHECK-THUMBV8: note: operand must be a register in range [r0, r14]

// CHECK-THUMBV7: error: operand must be a register in range [r0, r12] or r14
// CHECK-THUMBV8: error: operand must be a register in range [r0, r14]
// CHECK-NONARM-NEXT: movs pc, r0, lsl #0

// CHECK-NONARM: error: invalid instruction, any one of the following would fix this:
// CHECK-NONARM-NEXT: movs r0, pc, lsl #0
// CHECK-NONARM: invalid operand for instruction
// CHECK-NONARM: invalid operand for instruction
// CHECK-NONARM: error: invalid operand for instruction
// CHECK-NONARM: note: operand must be a register in range [r0, r14]
// CHECK-NONARM: note: invalid operand for instruction
// CHECK-NONARM: note: invalid operand for instruction

// CHECK-THUMBV7: error: operand must be a register in range [r0, r12] or r14
// CHECK-THUMBV8: error: operand must be a register in range [r0, r14]
// CHECK-NONARM-NEXT: movs pc, pc, lsl #0

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

// FIXME: We should consistently have the "requires ARMv8" error here
// CHECK-THUMBV7: error: invalid instruction, any one of the following would fix this:
// CHECK-THUMBV7: invalid operand for instruction
// CHECK-THUMBV7-NEXT: mov sp, sp, lsl #0
// CHECK-THUMBV7: note: operand must be a register in range [r0, r15]
// CHECK-THUMBV7: note: operand must be a register in range [r0, r12] or r14

// CHECK-THUMBV7: error: invalid instruction, any one of the following would fix this:
// CHECK-THUMBV7: invalid operand for instruction
// CHECK-THUMBV7-NEXT: movs sp, sp, lsl #0
// CHECK-THUMBV7: note: operand must be a register in range [r0, r14]
// CHECK-THUMBV7: note: operand must be a register in range [r0, r12] or r14

// CHECK-THUMBV7: error: invalid instruction, any one of the following would fix this:
// CHECK-THUMBV7: instruction variant requires ARMv8 or later
// CHECK-THUMBV7-NEXT: movs r0, sp, lsl #0
// CHECK-THUMBV7: note: operand must be a register in range [r0, r14]
// CHECK-THUMBV7: note: invalid operand for instruction
// CHECK-THUMBV7: note: instruction variant requires ARMv8 or later

// CHECK-THUMBV7: error: invalid instruction, any one of the following would fix this:
// CHECK-THUMBV7: invalid operand for instruction
// CHECK-THUMBV7-NEXT: movs sp, r0, lsl #0
// CHECK-THUMBV7: note: operand must be a register in range [r0, r14]
// CHECK-THUMBV7: note: operand must be a register in range [r0, r12] or r14

// CHECK-ARM: mov sp, sp @ encoding: [0x0d,0xd0,0xa0,0xe1]
// CHECK-ARM: movs sp, sp @ encoding: [0x0d,0xd0,0xb0,0xe1]
Expand Down
17 changes: 13 additions & 4 deletions llvm/test/MC/ARM/negative-immediates-fail.s
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,27 @@
.arm

ADC r0, r1, #0xFFFFFEEE
# CHECK: error: invalid operand for instruction
# CHECK: error: invalid instruction, any one of the following would fix this:
# CHECK: note: invalid operand for instruction
# CHECK: note: operand must be a register in range [r0, r15]
ADC r0, r1, #0xABFEABFF
# CHECK: error: invalid operand for instruction
# CHECK: error: invalid instruction, any one of the following would fix this:
# CHECK: note: invalid operand for instruction
# CHECK: note: operand must be a register in range [r0, r15]
ADC r0, r1, #0xFFFFFE02
# CHECK: error: invalid operand for instruction
# CHECK: error: invalid instruction, any one of the following would fix this:
# CHECK: note: invalid operand for instruction
# CHECK: note: operand must be a register in range [r0, r15]

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

ORR r0, r1, #0xFFFFFF00
# CHECK: error: invalid instruction, any one of the following would fix this:
# CHECK: note: invalid operand for instruction
# CHECK: note: operand must be a register in range [r0, r15]
# CHECK: note: instruction requires: thumb2
ORN r0, r1, #0xFFFFFF00
# CHECK: error: instruction requires: thumb2
2 changes: 2 additions & 0 deletions llvm/test/MC/ARM/negative-immediates-thumb1-fail.s
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ ADDs r1, r0, #0xFFFFFFF5
# CHECK-DAG: note: instruction requires: thumb2
# CHECK-DAG: note: invalid operand for instruction
# CHECK-DAG: note: operand must be an immediate in the range [0,7]
# CHECK-DAG: note: operand must be a register in range [r0, r7]

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

SUBs r0, #0xFFFFFEFF
# CHECK: error: invalid instruction, any one of the following would fix this:
Expand Down
2 changes: 1 addition & 1 deletion llvm/test/MC/ARM/register-token-source-loc.s
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
add sp, r0, #4
// CHECK: error: invalid instruction, any one of the following would fix this:
// CHECK: note: instruction requires: thumb2
// CHECK: note: invalid operand for instruction
// CHECK: note: operand must be a register sp
// CHECK-NEXT: {{^ add sp, r0, #4}}
// CHECK-NEXT: {{^ \^}}
// CHECK: note: too many operands for instruction
6 changes: 4 additions & 2 deletions llvm/test/MC/ARM/thumb-branch-errors.s
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,7 @@
@ CHECK: cbnz r2, #1
@ CHECK: error: branch target out of range
@ CHECK: beq #1
@ CHECK: error: invalid operand for instruction
@ CHECK: blx #2
@ CHECK: invalid operand for instruction
@ CHECK-NEXT: blx #2
@ CHECK: operand must be a register in range [r0, r15]
@ CHECK-NEXT: blx #2
Loading

0 comments on commit bbad419

Please sign in to comment.