[llvm-commits] [llvm] r135990 - in /llvm/trunk: lib/Target/ARM/ARMInstrInfo.td lib/Target/ARM/ARMInstrThumb2.td lib/Target/ARM/AsmParser/ARMAsmParser.cpp lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp lib/Target/ARM/Disassembler/ThumbDisassemblerCore.h lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp test/MC/ARM/basic-arm-instructions.s test/MC/ARM/diagnostics.s

Jim Grosbach grosbach at apple.com
Mon Jul 25 15:20:28 PDT 2011


Author: grosbach
Date: Mon Jul 25 17:20:28 2011
New Revision: 135990

URL: http://llvm.org/viewvc/llvm-project?rev=135990&view=rev
Log:
ARM assembly parsing and encoding for SSAT instruction.

Fix the Rn register encoding for both SSAT and USAT. Update the parsing of the
shift operand to correctly handle the allowed shift types and immediate ranges
and issue meaningful diagnostics when an illegal value or shift type is
specified. Add aliases to parse an ommitted shift operand (default value of
'lsl #0').

Add tests for diagnostics and proper encoding.

Modified:
    llvm/trunk/lib/Target/ARM/ARMInstrInfo.td
    llvm/trunk/lib/Target/ARM/ARMInstrThumb2.td
    llvm/trunk/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
    llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp
    llvm/trunk/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.h
    llvm/trunk/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp
    llvm/trunk/test/MC/ARM/basic-arm-instructions.s
    llvm/trunk/test/MC/ARM/diagnostics.s

Modified: llvm/trunk/lib/Target/ARM/ARMInstrInfo.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMInstrInfo.td?rev=135990&r1=135989&r2=135990&view=diff
==============================================================================
--- llvm/trunk/lib/Target/ARM/ARMInstrInfo.td (original)
+++ llvm/trunk/lib/Target/ARM/ARMInstrInfo.td Mon Jul 25 17:20:28 2011
@@ -395,12 +395,18 @@
 }
 
 // shift_imm: An integer that encodes a shift amount and the type of shift
-// (currently either asr or lsl) using the same encoding used for the
-// immediates in so_reg operands.
-def ShifterAsmOperand : AsmOperandClass { let Name = "Shifter"; }
+// (asr or lsl). The 6-bit immediate encodes as:
+//    {5}     0 ==> 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<i32> {
   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 @@
 
 // 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 @@
   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 @@
   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 @@
   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",
                 (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)>;

Modified: llvm/trunk/lib/Target/ARM/ARMInstrThumb2.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMInstrThumb2.td?rev=135990&r1=135989&r2=135990&view=diff
==============================================================================
--- llvm/trunk/lib/Target/ARM/ARMInstrThumb2.td (original)
+++ llvm/trunk/lib/Target/ARM/ARMInstrThumb2.td Mon Jul 25 17:20:28 2011
@@ -1918,8 +1918,8 @@
 
   let Inst{11-8}  = Rd;
   let Inst{19-16} = Rn;
-  let Inst{4-0}   = sat_imm{4-0};
-  let Inst{21}    = sh{6};
+  let Inst{4-0}   = sat_imm;
+  let Inst{21}    = sh{5};
   let Inst{14-12} = sh{4-2};
   let Inst{7-6}   = sh{1-0};
 }

Modified: llvm/trunk/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/AsmParser/ARMAsmParser.cpp?rev=135990&r1=135989&r2=135990&view=diff
==============================================================================
--- llvm/trunk/lib/Target/ARM/AsmParser/ARMAsmParser.cpp (original)
+++ llvm/trunk/lib/Target/ARM/AsmParser/ARMAsmParser.cpp Mon Jul 25 17:20:28 2011
@@ -127,6 +127,7 @@
     return parsePKHImm(O, "asr", 1, 32);
   }
   OperandMatchResultTy parseSetEndImm(SmallVectorImpl<MCParsedAsmOperand*>&);
+  OperandMatchResultTy parseShifterImm(SmallVectorImpl<MCParsedAsmOperand*>&);
 
   // Asm Match Converter Methods
   bool CvtLdWriteBackRegAddrMode2(MCInst &Inst, unsigned Opcode,
@@ -179,7 +180,7 @@
     SPRRegisterList,
     ShiftedRegister,
     ShiftedImmediate,
-    Shifter,
+    ShifterImmediate,
     Token
   } Kind;
 
@@ -239,9 +240,9 @@
     } Mem;
 
     struct {
-      ARM_AM::ShiftOpc ShiftTy;
+      bool isASR;
       unsigned Imm;
-    } Shift;
+    } ShifterImm;
     struct {
       ARM_AM::ShiftOpc ShiftTy;
       unsigned SrcReg;
@@ -296,8 +297,8 @@
     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 @@
   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 @@
   }
 
 
-  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 @@
     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 @@
   case Register:
     OS << "<register " << getReg() << ">";
     break;
-  case Shifter:
-    OS << "<shifter " << ARM_AM::getShiftOpcStr(Shift.ShiftTy) << ">";
+  case ShifterImmediate:
+    OS << "<shift " << (ShifterImm.isASR ? "asr" : "lsl")
+       << " #" << ShifterImm.Imm << ">";
     break;
   case ShiftedRegister:
     OS << "<so_reg_reg "
@@ -1705,6 +1708,73 @@
   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<MCParsedAsmOperand*> &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<MCConstantExpr>(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.

Modified: llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp?rev=135990&r1=135989&r2=135990&view=diff
==============================================================================
--- llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp (original)
+++ llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp Mon Jul 25 17:20:28 2011
@@ -1732,17 +1732,11 @@
                                                      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;
 }

Modified: llvm/trunk/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.h?rev=135990&r1=135989&r2=135990&view=diff
==============================================================================
--- llvm/trunk/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.h (original)
+++ llvm/trunk/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.h Mon Jul 25 17:20:28 2011
@@ -1615,17 +1615,11 @@
                                                      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;
 }

Modified: llvm/trunk/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp?rev=135990&r1=135989&r2=135990&view=diff
==============================================================================
--- llvm/trunk/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp (original)
+++ llvm/trunk/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp Mon Jul 25 17:20:28 2011
@@ -450,20 +450,12 @@
 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,

Modified: llvm/trunk/test/MC/ARM/basic-arm-instructions.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/ARM/basic-arm-instructions.s?rev=135990&r1=135989&r2=135990&view=diff
==============================================================================
--- llvm/trunk/test/MC/ARM/basic-arm-instructions.s (original)
+++ llvm/trunk/test/MC/ARM/basic-arm-instructions.s Mon Jul 25 17:20:28 2011
@@ -1614,6 +1614,23 @@
 @------------------------------------------------------------------------------
 @ FIXME: SRS
 @------------------------------------------------------------------------------
+
+
+ at ------------------------------------------------------------------------------
+@ SSAT
+ at ------------------------------------------------------------------------------
+	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*
 @------------------------------------------------------------------------------

Modified: llvm/trunk/test/MC/ARM/diagnostics.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/ARM/diagnostics.s?rev=135990&r1=135989&r2=135990&view=diff
==============================================================================
--- llvm/trunk/test/MC/ARM/diagnostics.s (original)
+++ llvm/trunk/test/MC/ARM/diagnostics.s Mon Jul 25 17:20:28 2011
@@ -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:                                   ^





More information about the llvm-commits mailing list