[ARM64] Add proper bounds checking/diagnostics to logical shifts
authorBradley Smith <bradley.smith@arm.com>
Mon, 12 May 2014 11:49:16 +0000 (11:49 +0000)
committerBradley Smith <bradley.smith@arm.com>
Mon, 12 May 2014 11:49:16 +0000 (11:49 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@208540 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/ARM64/ARM64InstrFormats.td
lib/Target/ARM64/ARM64InstrInfo.td
lib/Target/ARM64/AsmParser/ARM64AsmParser.cpp
test/MC/ARM64/diags.s

index 4e97a99ef68aabf753d50edd34cab953bee14269..8cbdaf558a8db53205c220ce34b72d30ba2ae5e0 100644 (file)
@@ -108,6 +108,18 @@ class ArithmeticShifterOperand<int width> : AsmOperandClass {
 def ArithmeticShifterOperand32 : ArithmeticShifterOperand<32>;
 def ArithmeticShifterOperand64 : ArithmeticShifterOperand<64>;
 
+// Shifter operand for logical register shifted encodings.
+class LogicalShifterOperand<int width> : AsmOperandClass {
+  let SuperClasses = [ShifterOperand];
+  let Name = "LogicalShifter" # width;
+  let PredicateMethod = "isLogicalShifter<" # width # ">";
+  let RenderMethod = "addLogicalShifterOperands";
+  let DiagnosticType = "AddSubRegShift" # width;
+}
+
+def LogicalShifterOperand32 : LogicalShifterOperand<32>;
+def LogicalShifterOperand64 : LogicalShifterOperand<64>;
+
 // Shifter operand for logical vector 128/64-bit shifted encodings.
 def LogicalVecShifterOperand : AsmOperandClass {
   let SuperClasses = [ShifterOperand];
@@ -525,20 +537,24 @@ def arith_shifted_reg64 : arith_shifted_reg<i64, GPR64, 64>;
 // An arithmetic shifter operand:
 //  {7-6} - shift type: 00 = lsl, 01 = lsr, 10 = asr, 11 = ror
 //  {5-0} - imm6
-def logical_shift : Operand<i32> {
+class logical_shift<int width> : Operand<i32> {
   let PrintMethod = "printShifter";
-  let ParserMatchClass = ShifterOperand;
+  let ParserMatchClass = !cast<AsmOperandClass>(
+                         "LogicalShifterOperand" # width);
 }
 
-class logical_shifted_reg<ValueType Ty, RegisterClass regclass>
+def logical_shift32 : logical_shift<32>;
+def logical_shift64 : logical_shift<64>;
+
+class logical_shifted_reg<ValueType Ty, RegisterClass regclass, Operand shiftop>
     : Operand<Ty>,
       ComplexPattern<Ty, 2, "SelectLogicalShiftedRegister", []> {
   let PrintMethod = "printShiftedRegister";
-  let MIOperandInfo = (ops regclass, logical_shift);
+  let MIOperandInfo = (ops regclass, shiftop);
 }
 
-def logical_shifted_reg32 : logical_shifted_reg<i32, GPR32>;
-def logical_shifted_reg64 : logical_shifted_reg<i64, GPR64>;
+def logical_shifted_reg32 : logical_shifted_reg<i32, GPR32, logical_shift32>;
+def logical_shifted_reg64 : logical_shifted_reg<i64, GPR64, logical_shift64>;
 
 // A logical vector shifter operand:
 //  {7-6} - shift type: 00 = lsl
index 46ba5bbb6584a6b6c167a0821bd76c3c568736b0..d674b918c8f964b50bdc7386d02f7e5c874ebe89 100644 (file)
@@ -671,9 +671,9 @@ def : InstAlias<"tst $src1, $src2",
                 (ANDSXrs XZR, GPR64:$src1, GPR64:$src2, 0)>;
 
 def : InstAlias<"tst $src1, $src2, $sh",
-                (ANDSWrs WZR, GPR32:$src1, GPR32:$src2, logical_shift:$sh)>;
+                (ANDSWrs WZR, GPR32:$src1, GPR32:$src2, logical_shift32:$sh)>;
 def : InstAlias<"tst $src1, $src2, $sh",
-                (ANDSXrs XZR, GPR64:$src1, GPR64:$src2, logical_shift:$sh)>;
+                (ANDSXrs XZR, GPR64:$src1, GPR64:$src2, logical_shift64:$sh)>;
 
 def : InstAlias<"mvn $Wd, $Wm",
                 (ORNWrs GPR32:$Wd, WZR, GPR32:$Wm, 0)>;
@@ -681,9 +681,9 @@ def : InstAlias<"mvn $Xd, $Xm",
                 (ORNXrs GPR64:$Xd, XZR, GPR64:$Xm, 0)>;
 
 def : InstAlias<"mvn $Wd, $Wm, $sh",
-                (ORNWrs GPR32:$Wd, WZR, GPR32:$Wm, logical_shift:$sh)>;
+                (ORNWrs GPR32:$Wd, WZR, GPR32:$Wm, logical_shift32:$sh)>;
 def : InstAlias<"mvn $Xd, $Xm, $sh",
-                (ORNXrs GPR64:$Xd, XZR, GPR64:$Xm, logical_shift:$sh)>;
+                (ORNXrs GPR64:$Xd, XZR, GPR64:$Xm, logical_shift64:$sh)>;
 
 def : Pat<(not GPR32:$Wm), (ORNWrr WZR, GPR32:$Wm)>;
 def : Pat<(not GPR64:$Xm), (ORNXrr XZR, GPR64:$Xm)>;
index b2583a0f12464f0729b4edfba40d1661fdb5845b..760c2fcb59c62552f73479ff684b817c611397d7 100644 (file)
@@ -845,6 +845,18 @@ public:
            ST == ARM64_AM::ASR) && ARM64_AM::getShiftValue(Shifter.Val) < width;
   }
 
+  template <unsigned width>
+  bool isLogicalShifter() const {
+    if (!isShifter())
+      return false;
+
+    // A logical shifter is LSL, LSR, ASR or ROR.
+    ARM64_AM::ShiftType ST = ARM64_AM::getShiftType(Shifter.Val);
+    return (ST == ARM64_AM::LSL || ST == ARM64_AM::LSR ||
+           ST == ARM64_AM::ASR || ST == ARM64_AM::ROR) &&
+           ARM64_AM::getShiftValue(Shifter.Val) < width;
+  }
+
   bool isMovImm32Shifter() const {
     if (!isShifter())
       return false;
@@ -1453,6 +1465,11 @@ public:
     Inst.addOperand(MCOperand::CreateImm(getShifter()));
   }
 
+  void addLogicalShifterOperands(MCInst &Inst, unsigned N) const {
+    assert(N == 1 && "Invalid number of operands!");
+    Inst.addOperand(MCOperand::CreateImm(getShifter()));
+  }
+
   void addMovImm32ShifterOperands(MCInst &Inst, unsigned N) const {
     assert(N == 1 && "Invalid number of operands!");
     Inst.addOperand(MCOperand::CreateImm(getShifter()));
@@ -3677,18 +3694,6 @@ bool ARM64AsmParser::validateInstruction(MCInst &Inst,
   // in the instructions being checked and this keeps the nested conditionals
   // to a minimum.
   switch (Inst.getOpcode()) {
-  case ARM64::ANDWrs:
-  case ARM64::ANDSWrs:
-  case ARM64::EORWrs:
-  case ARM64::ORRWrs: {
-    if (!Inst.getOperand(3).isImm())
-      return Error(Loc[3], "immediate value expected");
-    int64_t shifter = Inst.getOperand(3).getImm();
-    ARM64_AM::ShiftType ST = ARM64_AM::getShiftType(shifter);
-    if (ST == ARM64_AM::LSL && shifter > 31)
-      return Error(Loc[3], "shift value out of range");
-    return false;
-  }
   case ARM64::ADDSWri:
   case ARM64::ADDSXri:
   case ARM64::ADDWri:
index 9846450b20835fbd2dbe4f18bc94fa751197706c..c65ced5b5db523a17171ca5659935be104783989 100644 (file)
@@ -182,19 +182,19 @@ foo:
 
 ; logical instructions on 32-bit regs with shift > 31 is not legal
 orr w0, w0, w0, lsl #32
-; CHECK-ERRORS: error: shift value out of range
+; CHECK-ERRORS: error: expected 'lsl', 'lsr' or 'asr' with optional integer in range [0, 31]
 ; CHECK-ERRORS:        orr w0, w0, w0, lsl #32
 ; CHECK-ERRORS:                        ^
 eor w0, w0, w0, lsl #32
-; CHECK-ERRORS: error: shift value out of range
+; CHECK-ERRORS: error: expected 'lsl', 'lsr' or 'asr' with optional integer in range [0, 31]
 ; CHECK-ERRORS:        eor w0, w0, w0, lsl #32
 ; CHECK-ERRORS:                        ^
 and w0, w0, w0, lsl #32
-; CHECK-ERRORS: error: shift value out of range
+; CHECK-ERRORS: error: expected 'lsl', 'lsr' or 'asr' with optional integer in range [0, 31]
 ; CHECK-ERRORS:        and w0, w0, w0, lsl #32
 ; CHECK-ERRORS:                        ^
 ands w0, w0, w0, lsl #32
-; CHECK-ERRORS: error: shift value out of range
+; CHECK-ERRORS: error: expected 'lsl', 'lsr' or 'asr' with optional integer in range [0, 31]
 ; CHECK-ERRORS:        ands w0, w0, w0, lsl #32
 ; CHECK-ERRORS:                        ^