diff --git a/lib/Target/ARM/ARMInstrInfo.td b/lib/Target/ARM/ARMInstrInfo.td index 53410579de1..6e9743ffad5 100644 --- a/lib/Target/ARM/ARMInstrInfo.td +++ b/lib/Target/ARM/ARMInstrInfo.td @@ -395,12 +395,18 @@ def rot_imm : Operand, ImmLeaf lsl +// 1 asr +// {4-0} imm5 shift amount. +// asr #32 encoded as imm5 == 0. +def ShifterImmAsmOperand : AsmOperandClass { + let Name = "ShifterImm"; + let ParserMethod = "parseShifterImm"; +} def shift_imm : Operand { let PrintMethod = "printShiftImmOperand"; - let ParserMatchClass = ShifterAsmOperand; + let ParserMatchClass = ShifterImmAsmOperand; } // shifter_operand operands: so_reg_reg, so_reg_imm, and so_imm. @@ -2688,8 +2694,8 @@ def USADA8 : AI<(outs GPR:$Rd), (ins GPR:$Rn, GPR:$Rm, GPR:$Ra), // Signed/Unsigned saturate -- for disassembly only -def SSAT : AI<(outs GPR:$Rd), (ins imm1_32:$sat_imm, GPR:$a, shift_imm:$sh), - SatFrm, NoItinerary, "ssat", "\t$Rd, $sat_imm, $a$sh", []> { +def SSAT : AI<(outs GPR:$Rd), (ins imm1_32:$sat_imm, GPR:$Rn, shift_imm:$sh), + SatFrm, NoItinerary, "ssat", "\t$Rd, $sat_imm, $Rn$sh", []> { bits<4> Rd; bits<5> sat_imm; bits<4> Rn; @@ -2698,8 +2704,8 @@ def SSAT : AI<(outs GPR:$Rd), (ins imm1_32:$sat_imm, GPR:$a, shift_imm:$sh), let Inst{5-4} = 0b01; let Inst{20-16} = sat_imm; let Inst{15-12} = Rd; - let Inst{11-7} = sh{7-3}; - let Inst{6} = sh{0}; + let Inst{11-7} = sh{4-0}; + let Inst{6} = sh{5}; let Inst{3-0} = Rn; } @@ -2715,9 +2721,8 @@ def SSAT16 : AI<(outs GPR:$Rd), (ins imm1_32:$sat_imm, GPR:$Rn), SatFrm, let Inst{3-0} = Rn; } -def USAT : AI<(outs GPR:$Rd), (ins i32imm:$sat_imm, GPR:$a, shift_imm:$sh), - SatFrm, NoItinerary, "usat", "\t$Rd, $sat_imm, $a$sh", - [/* For disassembly only; pattern left blank */]> { +def USAT : AI<(outs GPR:$Rd), (ins i32imm:$sat_imm, GPR:$Rn, shift_imm:$sh), + SatFrm, NoItinerary, "usat", "\t$Rd, $sat_imm, $Rn$sh", []> { bits<4> Rd; bits<5> sat_imm; bits<4> Rn; @@ -2725,8 +2730,8 @@ def USAT : AI<(outs GPR:$Rd), (ins i32imm:$sat_imm, GPR:$a, shift_imm:$sh), let Inst{27-21} = 0b0110111; let Inst{5-4} = 0b01; let Inst{15-12} = Rd; - let Inst{11-7} = sh{7-3}; - let Inst{6} = sh{0}; + let Inst{11-7} = sh{4-0}; + let Inst{6} = sh{5}; let Inst{20-16} = sat_imm; let Inst{3-0} = Rn; } @@ -4278,3 +4283,7 @@ def : InstAlias<"rsc${s}${p} $Rdn, $shift", def : InstAlias<"rsc${s}${p} $Rdn, $shift", (RSCrsr GPR:$Rdn, GPR:$Rdn, so_reg_reg:$shift, pred:$p, cc_out:$s)>, Requires<[IsARM]>; + +// SSAT optional shift operand. +def : InstAlias<"ssat${p} $Rd, $sat_imm, $Rn", + (SSAT GPR:$Rd, imm1_32:$sat_imm, GPR:$Rn, 0, pred:$p)>; diff --git a/lib/Target/ARM/ARMInstrThumb2.td b/lib/Target/ARM/ARMInstrThumb2.td index 33a246f2ed3..808ae51a600 100644 --- a/lib/Target/ARM/ARMInstrThumb2.td +++ b/lib/Target/ARM/ARMInstrThumb2.td @@ -1918,8 +1918,8 @@ class T2SatI&); + OperandMatchResultTy parseShifterImm(SmallVectorImpl&); // Asm Match Converter Methods bool CvtLdWriteBackRegAddrMode2(MCInst &Inst, unsigned Opcode, @@ -179,7 +180,7 @@ class ARMOperand : public MCParsedAsmOperand { SPRRegisterList, ShiftedRegister, ShiftedImmediate, - Shifter, + ShifterImmediate, Token } Kind; @@ -239,9 +240,9 @@ class ARMOperand : public MCParsedAsmOperand { } Mem; struct { - ARM_AM::ShiftOpc ShiftTy; + bool isASR; unsigned Imm; - } Shift; + } ShifterImm; struct { ARM_AM::ShiftOpc ShiftTy; unsigned SrcReg; @@ -296,8 +297,8 @@ public: case ProcIFlags: IFlags = o.IFlags; break; - case Shifter: - Shift = o.Shift; + case ShifterImmediate: + ShifterImm = o.ShifterImm; break; case ShiftedRegister: RegShiftedReg = o.RegShiftedReg; @@ -505,7 +506,7 @@ public: bool isToken() const { return Kind == Token; } bool isMemBarrierOpt() const { return Kind == MemBarrierOpt; } bool isMemory() const { return Kind == Memory; } - bool isShifter() const { return Kind == Shifter; } + bool isShifterImm() const { return Kind == ShifterImmediate; } bool isRegShiftedReg() const { return Kind == ShiftedRegister; } bool isRegShiftedImm() const { return Kind == ShiftedImmediate; } bool isMemMode2() const { @@ -656,10 +657,10 @@ public: } - void addShifterOperands(MCInst &Inst, unsigned N) const { + void addShifterImmOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); - Inst.addOperand(MCOperand::CreateImm( - ARM_AM::getSORegOpc(Shift.ShiftTy, 0))); + Inst.addOperand(MCOperand::CreateImm((ShifterImm.isASR << 5) | + ShifterImm.Imm)); } void addRegListOperands(MCInst &Inst, unsigned N) const { @@ -962,10 +963,11 @@ public: return Op; } - static ARMOperand *CreateShifter(ARM_AM::ShiftOpc ShTy, + static ARMOperand *CreateShifterImm(bool isASR, unsigned Imm, SMLoc S, SMLoc E) { - ARMOperand *Op = new ARMOperand(Shifter); - Op->Shift.ShiftTy = ShTy; + ARMOperand *Op = new ARMOperand(ShifterImmediate); + Op->ShifterImm.isASR = isASR; + Op->ShifterImm.Imm = Imm; Op->StartLoc = S; Op->EndLoc = E; return Op; @@ -1127,8 +1129,9 @@ void ARMOperand::print(raw_ostream &OS) const { case Register: OS << ""; break; - case Shifter: - OS << ""; + case ShifterImmediate: + OS << ""; break; case ShiftedRegister: OS << " &Operands) { return MatchOperand_Success; } +/// parseShifterImm - Parse the shifter immediate operand for SSAT/USAT +/// instructions. Legal values are: +/// lsl #n 'n' in [0,31] +/// asr #n 'n' in [1,32] +/// n == 32 encoded as n == 0. +ARMAsmParser::OperandMatchResultTy ARMAsmParser:: +parseShifterImm(SmallVectorImpl &Operands) { + const AsmToken &Tok = Parser.getTok(); + SMLoc S = Tok.getLoc(); + if (Tok.isNot(AsmToken::Identifier)) { + Error(S, "shift operator 'asr' or 'lsl' expected"); + return MatchOperand_ParseFail; + } + StringRef ShiftName = Tok.getString(); + bool isASR; + if (ShiftName == "lsl" || ShiftName == "LSL") + isASR = false; + else if (ShiftName == "asr" || ShiftName == "ASR") + isASR = true; + else { + Error(S, "shift operator 'asr' or 'lsl' expected"); + return MatchOperand_ParseFail; + } + Parser.Lex(); // Eat the operator. + + // A '#' and a shift amount. + if (Parser.getTok().isNot(AsmToken::Hash)) { + Error(Parser.getTok().getLoc(), "'#' expected"); + return MatchOperand_ParseFail; + } + Parser.Lex(); // Eat hash token. + + const MCExpr *ShiftAmount; + SMLoc E = Parser.getTok().getLoc(); + if (getParser().ParseExpression(ShiftAmount)) { + Error(E, "malformed shift expression"); + return MatchOperand_ParseFail; + } + const MCConstantExpr *CE = dyn_cast(ShiftAmount); + if (!CE) { + Error(E, "shift amount must be an immediate"); + return MatchOperand_ParseFail; + } + + int64_t Val = CE->getValue(); + if (isASR) { + // Shift amount must be in [1,32] + if (Val < 1 || Val > 32) { + Error(E, "'asr' shift amount must be in range [1,32]"); + return MatchOperand_ParseFail; + } + // asr #32 encoded as asr #0. + if (Val == 32) Val = 0; + } else { + // Shift amount must be in [1,32] + if (Val < 0 || Val > 31) { + Error(E, "'lsr' shift amount must be in range [0,31]"); + return MatchOperand_ParseFail; + } + } + + E = Parser.getTok().getLoc(); + Operands.push_back(ARMOperand::CreateShifterImm(isASR, Val, S, E)); + + return MatchOperand_Success; +} + /// CvtLdWriteBackRegAddrMode2 - Convert parsed operands to MCInst. /// Needed here because the Asm Gen Matcher can't handle properly tied operands /// when they refer multiple MIOperands inside a single one. diff --git a/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp b/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp index 38c77d479db..07d9f8ebc77 100644 --- a/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp +++ b/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp @@ -1732,17 +1732,11 @@ static bool DisassembleSatFrm(MCInst &MI, unsigned Opcode, uint32_t insn, decodeRm(insn)))); if (NumOpsAdded == 4) { - ARM_AM::ShiftOpc Opc = (slice(insn, 6, 6) != 0 ? ARM_AM::asr : ARM_AM::lsl); + // Inst{6} encodes the shift type. + bool isASR = slice(insn, 6, 6); // Inst{11-7} encodes the imm5 shift amount. unsigned ShAmt = slice(insn, 11, 7); - if (ShAmt == 0) { - // A8.6.183. Possible ASR shift amount of 32... - if (Opc == ARM_AM::asr) - ShAmt = 32; - else - Opc = ARM_AM::no_shift; - } - MI.addOperand(MCOperand::CreateImm(ARM_AM::getSORegOpc(Opc, ShAmt))); + MI.addOperand(MCOperand::CreateImm(isASR << 5 | ShAmt)); } return true; } diff --git a/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.h b/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.h index 7ad958f51a7..694ffe6e991 100644 --- a/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.h +++ b/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.h @@ -1615,17 +1615,11 @@ static bool DisassembleThumb2Sat(MCInst &MI, unsigned Opcode, uint32_t insn, decodeRn(insn)))); if (NumOpsAdded == 4) { - ARM_AM::ShiftOpc Opc = (slice(insn, 21, 21) != 0 ? - ARM_AM::asr : ARM_AM::lsl); - // Inst{14-12:7-6} encodes the imm5 shift amount. - unsigned ShAmt = slice(insn, 14, 12) << 2 | slice(insn, 7, 6); - if (ShAmt == 0) { - if (Opc == ARM_AM::asr) - ShAmt = 32; - else - Opc = ARM_AM::no_shift; - } - MI.addOperand(MCOperand::CreateImm(ARM_AM::getSORegOpc(Opc, ShAmt))); + // Inst{6} encodes the shift type. + bool isASR = slice(insn, 6, 6); + // Inst{11-7} encodes the imm5 shift amount. + unsigned ShAmt = slice(insn, 11, 7); + MI.addOperand(MCOperand::CreateImm(isASR << 5 | ShAmt)); } return true; } diff --git a/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp b/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp index c130d0e8fa2..296080a8174 100644 --- a/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp +++ b/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp @@ -450,20 +450,12 @@ void ARMInstPrinter::printMemBOption(const MCInst *MI, unsigned OpNum, void ARMInstPrinter::printShiftImmOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O) { unsigned ShiftOp = MI->getOperand(OpNum).getImm(); - ARM_AM::ShiftOpc Opc = ARM_AM::getSORegShOp(ShiftOp); - switch (Opc) { - case ARM_AM::no_shift: - return; - case ARM_AM::lsl: - O << ", lsl #"; - break; - case ARM_AM::asr: - O << ", asr #"; - break; - default: - assert(0 && "unexpected shift opcode for shift immediate operand"); - } - O << ARM_AM::getSORegOffset(ShiftOp); + bool isASR = (ShiftOp & (1 << 5)) != 0; + unsigned Amt = ShiftOp & 0x1f; + if (isASR) + O << ", asr #" << (Amt == 0 ? 32 : Amt); + else if (Amt) + O << ", lsl #" << Amt; } void ARMInstPrinter::printPKHLSLShiftImm(const MCInst *MI, unsigned OpNum, diff --git a/test/MC/ARM/basic-arm-instructions.s b/test/MC/ARM/basic-arm-instructions.s index b1dec554539..0439e70c441 100644 --- a/test/MC/ARM/basic-arm-instructions.s +++ b/test/MC/ARM/basic-arm-instructions.s @@ -1614,6 +1614,23 @@ _func: @------------------------------------------------------------------------------ @ FIXME: SRS @------------------------------------------------------------------------------ + + +@------------------------------------------------------------------------------ +@ SSAT +@------------------------------------------------------------------------------ + ssat r8, #1, r10 + ssat r8, #1, r10, lsl #0 + ssat r8, #1, r10, lsl #31 + ssat r8, #1, r10, asr #32 + ssat r8, #1, r10, asr #1 + +@ CHECK: ssat r8, #1, r10 @ encoding: [0x1a,0x80,0xa0,0xe6] +@ CHECK: ssat r8, #1, r10 @ encoding: [0x1a,0x80,0xa0,0xe6] +@ CHECK: ssat r8, #1, r10, lsl #31 @ encoding: [0x9a,0x8f,0xa0,0xe6] +@ CHECK: ssat r8, #1, r10, asr #32 @ encoding: [0x5a,0x80,0xa0,0xe6] +@ CHECK: ssat r8, #1, r10, asr #1 @ encoding: [0xda,0x80,0xa0,0xe6] + @------------------------------------------------------------------------------ @ STM* @------------------------------------------------------------------------------ diff --git a/test/MC/ARM/diagnostics.s b/test/MC/ARM/diagnostics.s index 305a5fa65e1..a8b2d9d4faa 100644 --- a/test/MC/ARM/diagnostics.s +++ b/test/MC/ARM/diagnostics.s @@ -160,3 +160,43 @@ @ CHECK: error: 'be' or 'le' operand expected @ CHECK: setend 1 @ CHECK: ^ + + + @ Out of range immediates and bad shift types for SSAT + ssat r8, #0, r10, lsl #8 + ssat r8, #33, r10, lsl #8 + ssat r8, #1, r10, lsl #-1 + ssat r8, #1, r10, lsl #32 + ssat r8, #1, r10, asr #0 + ssat r8, #1, r10, asr #33 + ssat r8, #1, r10, lsr #5 + ssat r8, #1, r10, lsl fred + ssat r8, #1, r10, lsl #fred + +@ CHECK: error: invalid operand for instruction +@ CHECK: ssat r8, #0, r10, lsl #8 +@ CHECK: ^ +@ CHECK: error: invalid operand for instruction +@ CHECK: ssat r8, #33, r10, lsl #8 +@ CHECK: ^ +@ CHECK: error: 'lsr' shift amount must be in range [0,31] +@ CHECK: ssat r8, #1, r10, lsl #-1 +@ CHECK: ^ +@ CHECK: error: 'lsr' shift amount must be in range [0,31] +@ CHECK: ssat r8, #1, r10, lsl #32 +@ CHECK: ^ +@ CHECK: error: 'asr' shift amount must be in range [1,32] +@ CHECK: ssat r8, #1, r10, asr #0 +@ CHECK: ^ +@ CHECK: error: 'asr' shift amount must be in range [1,32] +@ CHECK: ssat r8, #1, r10, asr #33 +@ CHECK: ^ +@ CHECK: error: shift operator 'asr' or 'lsl' expected +@ CHECK: ssat r8, #1, r10, lsr #5 +@ CHECK: ^ +@ CHECK: error: '#' expected +@ CHECK: ssat r8, #1, r10, lsl fred +@ CHECK: ^ +@ CHECK: error: shift amount must be an immediate +@ CHECK: ssat r8, #1, r10, lsl #fred +@ CHECK: ^