Index: lib/Target/ARM64/ARM64InstrFormats.td =================================================================== --- lib/Target/ARM64/ARM64InstrFormats.td +++ lib/Target/ARM64/ARM64InstrFormats.td @@ -2183,6 +2183,7 @@ class MemROAsmOperand : AsmOperandClass { let Name = "MemoryRegisterOffset"#sz; + let DiagnosticType = "InvalidMemoryRegisterOffset"#sz; } def MemROAsmOperand8 : MemROAsmOperand<8>; Index: lib/Target/ARM64/AsmParser/ARM64AsmParser.cpp =================================================================== --- lib/Target/ARM64/AsmParser/ARM64AsmParser.cpp +++ lib/Target/ARM64/AsmParser/ARM64AsmParser.cpp @@ -847,6 +847,10 @@ (Shift == 8 || Shift == 16); } + bool isMemoryRegisterOffset() const { + return isMem() && Mem.Mode == RegisterOffset; + } + bool isMemoryRegisterOffset8() const { return isMem() && Mem.Mode == RegisterOffset && Mem.ShiftVal == 0; } @@ -3873,6 +3877,16 @@ return Error(Loc, "index must be a multiple of 8 in range [0, 32760]."); case Match_InvalidMemoryIndexed128: return Error(Loc, "index must be a multiple of 16 in range [0, 65520]."); + case Match_InvalidMemoryRegisterOffset8: + return Error(Loc, "immediate must be an integer 0."); + case Match_InvalidMemoryRegisterOffset16: + return Error(Loc, "immediate must be an integer either 0 or 1."); + case Match_InvalidMemoryRegisterOffset32: + return Error(Loc, "immediate must be an integer either 0 or 2."); + case Match_InvalidMemoryRegisterOffset64: + return Error(Loc, "immediate must be an integer either 0 or 3."); + case Match_InvalidMemoryRegisterOffset128: + return Error(Loc, "immediate must be an integer either 0 or 4."); case Match_InvalidImm0_7: return Error(Loc, "immediate must be an integer in range [0, 7]."); case Match_InvalidImm0_15: @@ -4405,16 +4419,73 @@ if (Operands.size() == ErrorInfo + 1 && !((ARM64Operand *)Operands[ErrorInfo])->isImm() && !Tok.startswith("stur") && !Tok.startswith("ldur")) { - // whether we want an Indexed64 or Indexed32 diagnostic depends on - // the register class of the previous operand. Default to 64 in case - // we see something unexpected. + // The diagnostic we need depends on the instruction names, the register + // class of the previous operand and instruction format. Default to 64 + // in case we see something unexpected. MatchResult = Match_InvalidMemoryIndexed64; if (ErrorInfo) { + ARM64Operand *ErrorOp = (ARM64Operand *)Operands[ErrorInfo]; ARM64Operand *PrevOp = (ARM64Operand *)Operands[ErrorInfo - 1]; - if (PrevOp->isReg() && - ARM64MCRegisterClasses[ARM64::GPR32RegClassID].contains( - PrevOp->getReg())) - MatchResult = Match_InvalidMemoryIndexed32; + if (Tok.startswith("ldrb") || Tok.startswith("strb")) { + if (ErrorOp->isMemoryRegisterOffset()) + MatchResult = Match_InvalidMemoryRegisterOffset8; + else + MatchResult = Match_InvalidMemoryIndexed8; + } else if (Tok.startswith("ldrh") || Tok.startswith("strh")) { + if (ErrorOp->isMemoryRegisterOffset()) + MatchResult = Match_InvalidMemoryRegisterOffset16; + else + MatchResult = Match_InvalidMemoryIndexed16; + } else if (PrevOp->isReg() && + ARM64MCRegisterClasses[ARM64::GPR32RegClassID].contains( + PrevOp->getReg())) { + if (ErrorOp->isMemoryRegisterOffset()) + MatchResult = Match_InvalidMemoryRegisterOffset32; + else + MatchResult = Match_InvalidMemoryIndexed32; + } else if (PrevOp->isReg() && + ARM64MCRegisterClasses[ARM64::GPR64RegClassID].contains( + PrevOp->getReg())) { + if (ErrorOp->isMemoryRegisterOffset()) + MatchResult = Match_InvalidMemoryRegisterOffset64; + else + MatchResult = Match_InvalidMemoryIndexed64; + } else if (PrevOp->isReg() && + ARM64MCRegisterClasses[ARM64::FPR8RegClassID].contains( + PrevOp->getReg())) { + if (ErrorOp->isMemoryRegisterOffset()) + MatchResult = Match_InvalidMemoryRegisterOffset8; + else + MatchResult = Match_InvalidMemoryIndexed8; + } else if (PrevOp->isReg() && + ARM64MCRegisterClasses[ARM64::FPR16RegClassID].contains( + PrevOp->getReg())) { + if (ErrorOp->isMemoryRegisterOffset()) + MatchResult = Match_InvalidMemoryRegisterOffset16; + else + MatchResult = Match_InvalidMemoryIndexed16; + } else if (PrevOp->isReg() && + ARM64MCRegisterClasses[ARM64::FPR32RegClassID].contains( + PrevOp->getReg())) { + if (ErrorOp->isMemoryRegisterOffset()) + MatchResult = Match_InvalidMemoryRegisterOffset32; + else + MatchResult = Match_InvalidMemoryIndexed32; + } else if (PrevOp->isReg() && + ARM64MCRegisterClasses[ARM64::FPR64RegClassID].contains( + PrevOp->getReg())) { + if (ErrorOp->isMemoryRegisterOffset()) + MatchResult = Match_InvalidMemoryRegisterOffset64; + else + MatchResult = Match_InvalidMemoryIndexed64; + } else if (PrevOp->isReg() && + ARM64MCRegisterClasses[ARM64::FPR128RegClassID].contains( + PrevOp->getReg())) { + if (ErrorOp->isMemoryRegisterOffset()) + MatchResult = Match_InvalidMemoryRegisterOffset128; + else + MatchResult = Match_InvalidMemoryIndexed128; + } } } SMLoc ErrorLoc = ((ARM64Operand *)Operands[ErrorInfo])->getStartLoc(); Index: test/MC/ARM64/diags.s =================================================================== --- test/MC/ARM64/diags.s +++ test/MC/ARM64/diags.s @@ -73,6 +73,44 @@ ; CHECK-ERRORS: ldur x0, [x1, #-257] ; CHECK-ERRORS: ^ +ldrb w1 , [x3, w3, sxtw #4] +ldrh w1 , [x3, w3, sxtw #4] +ldr w1 , [x3, w3, sxtw #4] +ldr x1 , [x3, w3, sxtw #4] +ldr b1 , [x3, w3, sxtw #4] +ldr h1 , [x3, w3, sxtw #4] +ldr s1 , [x3, w3, sxtw #4] +ldr d1 , [x3, w3, sxtw #4] +ldr q1 , [x3, w3, sxtw #1] + +; CHECK-ERRORS: error: immediate must be an integer 0. +; CHECK-ERRORS:ldrb w1 , [x3, w3, sxtw #4] +; CHECK-ERRORS: ^ +; CHECK-ERRORS: error: immediate must be an integer either 0 or 1. +; CHECK-ERRORS:ldrh w1 , [x3, w3, sxtw #4] +; CHECK-ERRORS: ^ +; CHECK-ERRORS: error: immediate must be an integer either 0 or 2. +; CHECK-ERRORS:ldr w1 , [x3, w3, sxtw #4] +; CHECK-ERRORS: ^ +; CHECK-ERRORS: error: immediate must be an integer either 0 or 3. +; CHECK-ERRORS:ldr x1 , [x3, w3, sxtw #4] +; CHECK-ERRORS: ^ +; CHECK-ERRORS: error: immediate must be an integer 0. +; CHECK-ERRORS:ldr b1 , [x3, w3, sxtw #4] +; CHECK-ERRORS: ^ +; CHECK-ERRORS: error: immediate must be an integer either 0 or 1. +; CHECK-ERRORS:ldr h1 , [x3, w3, sxtw #4] +; CHECK-ERRORS: ^ +; CHECK-ERRORS: error: immediate must be an integer either 0 or 2. +; CHECK-ERRORS:ldr s1 , [x3, w3, sxtw #4] +; CHECK-ERRORS: ^ +; CHECK-ERRORS: error: immediate must be an integer either 0 or 3. +; CHECK-ERRORS:ldr d1 , [x3, w3, sxtw #4] +; CHECK-ERRORS: ^ +; CHECK-ERRORS: error: immediate must be an integer either 0 or 4. +; CHECK-ERRORS:ldr q1 , [x3, w3, sxtw #1] +; CHECK-ERRORS: ^ + ; Check that register offset addressing modes only accept 32-bit offset ; registers when using uxtw/sxtw extends. Everything else requires a 64-bit