mirror of
				https://github.com/c64scene-ar/llvm-6502.git
				synced 2025-11-03 14:21:30 +00:00 
			
		
		
		
	Flesh out ARM Parser support for shifted-register operands.
Now works for parsing register shifted register and register shifted immediate arithmetic instructions, including the 'rrx' rotate with extend. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@135049 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
		@@ -412,14 +412,20 @@ def shift_imm : Operand<i32> {
 | 
			
		||||
  let ParserMatchClass = ShifterAsmOperand;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
def ShiftedRegAsmOperand : AsmOperandClass {
 | 
			
		||||
  let Name = "ShiftedReg";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// shifter_operand operands: so_reg and so_imm.
 | 
			
		||||
def so_reg : Operand<i32>,    // reg reg imm
 | 
			
		||||
             ComplexPattern<i32, 3, "SelectShifterOperandReg",
 | 
			
		||||
                            [shl,srl,sra,rotr]> {
 | 
			
		||||
  let EncoderMethod = "getSORegOpValue";
 | 
			
		||||
  let PrintMethod = "printSORegOperand";
 | 
			
		||||
  let ParserMatchClass = ShiftedRegAsmOperand;
 | 
			
		||||
  let MIOperandInfo = (ops GPR, GPR, shift_imm);
 | 
			
		||||
}
 | 
			
		||||
// FIXME: Does this need to be distinct from so_reg?
 | 
			
		||||
def shift_so_reg : Operand<i32>,    // reg reg imm
 | 
			
		||||
                   ComplexPattern<i32, 3, "SelectShiftShifterOperandReg",
 | 
			
		||||
                                  [shl,srl,sra,rotr]> {
 | 
			
		||||
 
 | 
			
		||||
@@ -164,6 +164,7 @@ class ARMOperand : public MCParsedAsmOperand {
 | 
			
		||||
    RegisterList,
 | 
			
		||||
    DPRRegisterList,
 | 
			
		||||
    SPRRegisterList,
 | 
			
		||||
    ShiftedRegister,
 | 
			
		||||
    Shifter,
 | 
			
		||||
    Token
 | 
			
		||||
  } Kind;
 | 
			
		||||
@@ -225,8 +226,14 @@ class ARMOperand : public MCParsedAsmOperand {
 | 
			
		||||
 | 
			
		||||
    struct {
 | 
			
		||||
      ARM_AM::ShiftOpc ShiftTy;
 | 
			
		||||
      unsigned RegNum;
 | 
			
		||||
      unsigned Imm;
 | 
			
		||||
    } Shift;
 | 
			
		||||
    struct {
 | 
			
		||||
      ARM_AM::ShiftOpc ShiftTy;
 | 
			
		||||
      unsigned SrcReg;
 | 
			
		||||
      unsigned ShiftReg;
 | 
			
		||||
      unsigned ShiftImm;
 | 
			
		||||
    } ShiftedReg;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  ARMOperand(KindTy K) : MCParsedAsmOperand(), Kind(K) {}
 | 
			
		||||
@@ -273,6 +280,9 @@ public:
 | 
			
		||||
    case Shifter:
 | 
			
		||||
      Shift = o.Shift;
 | 
			
		||||
      break;
 | 
			
		||||
    case ShiftedRegister:
 | 
			
		||||
      ShiftedReg = o.ShiftedReg;
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -392,6 +402,7 @@ public:
 | 
			
		||||
  bool isMemBarrierOpt() const { return Kind == MemBarrierOpt; }
 | 
			
		||||
  bool isMemory() const { return Kind == Memory; }
 | 
			
		||||
  bool isShifter() const { return Kind == Shifter; }
 | 
			
		||||
  bool isShiftedReg() const { return Kind == ShiftedRegister; }
 | 
			
		||||
  bool isMemMode2() const {
 | 
			
		||||
    if (getMemAddrMode() != ARMII::AddrMode2)
 | 
			
		||||
      return false;
 | 
			
		||||
@@ -522,6 +533,18 @@ public:
 | 
			
		||||
    Inst.addOperand(MCOperand::CreateReg(getReg()));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void addShiftedRegOperands(MCInst &Inst, unsigned N) const {
 | 
			
		||||
    assert(N == 3 && "Invalid number of operands!");
 | 
			
		||||
    assert(isShiftedReg() && "addShiftedRegOperands() on non ShiftedReg!");
 | 
			
		||||
    assert((ShiftedReg.ShiftReg == 0 ||
 | 
			
		||||
            ARM_AM::getSORegOffset(ShiftedReg.ShiftImm) == 0) &&
 | 
			
		||||
           "Invalid shifted register operand!");
 | 
			
		||||
    Inst.addOperand(MCOperand::CreateReg(ShiftedReg.SrcReg));
 | 
			
		||||
    Inst.addOperand(MCOperand::CreateReg(ShiftedReg.ShiftReg));
 | 
			
		||||
    Inst.addOperand(MCOperand::CreateImm(
 | 
			
		||||
      ARM_AM::getSORegOpc(ShiftedReg.ShiftTy, ShiftedReg.ShiftImm)));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void addShifterOperands(MCInst &Inst, unsigned N) const {
 | 
			
		||||
    assert(N == 1 && "Invalid number of operands!");
 | 
			
		||||
    Inst.addOperand(MCOperand::CreateImm(
 | 
			
		||||
@@ -743,6 +766,21 @@ public:
 | 
			
		||||
    return Op;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static ARMOperand *CreateShiftedRegister(ARM_AM::ShiftOpc ShTy,
 | 
			
		||||
                                           unsigned SrcReg,
 | 
			
		||||
                                           unsigned ShiftReg,
 | 
			
		||||
                                           unsigned ShiftImm,
 | 
			
		||||
                                           SMLoc S, SMLoc E) {
 | 
			
		||||
    ARMOperand *Op = new ARMOperand(ShiftedRegister);
 | 
			
		||||
    Op->ShiftedReg.ShiftTy = ShTy;
 | 
			
		||||
    Op->ShiftedReg.SrcReg = SrcReg;
 | 
			
		||||
    Op->ShiftedReg.ShiftReg = ShiftReg;
 | 
			
		||||
    Op->ShiftedReg.ShiftImm = ShiftImm;
 | 
			
		||||
    Op->StartLoc = S;
 | 
			
		||||
    Op->EndLoc = E;
 | 
			
		||||
    return Op;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static ARMOperand *CreateShifter(ARM_AM::ShiftOpc ShTy,
 | 
			
		||||
                                   SMLoc S, SMLoc E) {
 | 
			
		||||
    ARMOperand *Op = new ARMOperand(Shifter);
 | 
			
		||||
@@ -907,7 +945,15 @@ void ARMOperand::print(raw_ostream &OS) const {
 | 
			
		||||
    OS << "<register " << getReg() << ">";
 | 
			
		||||
    break;
 | 
			
		||||
  case Shifter:
 | 
			
		||||
    OS << "<shifter " << getShiftOpcStr(Shift.ShiftTy) << ">";
 | 
			
		||||
    OS << "<shifter " << ARM_AM::getShiftOpcStr(Shift.ShiftTy) << ">";
 | 
			
		||||
    break;
 | 
			
		||||
  case ShiftedRegister:
 | 
			
		||||
    OS << "<so_reg"
 | 
			
		||||
       << ShiftedReg.SrcReg
 | 
			
		||||
       << ARM_AM::getShiftOpcStr(ARM_AM::getSORegShOp(ShiftedReg.ShiftImm))
 | 
			
		||||
       << ", " << ShiftedReg.ShiftReg << ", "
 | 
			
		||||
       << ARM_AM::getSORegOffset(ShiftedReg.ShiftImm)
 | 
			
		||||
       << ">";
 | 
			
		||||
    break;
 | 
			
		||||
  case RegisterList:
 | 
			
		||||
  case DPRRegisterList:
 | 
			
		||||
@@ -994,13 +1040,56 @@ bool ARMAsmParser::TryParseShiftRegister(
 | 
			
		||||
  if (ShiftTy == ARM_AM::no_shift)
 | 
			
		||||
    return true;
 | 
			
		||||
 | 
			
		||||
  Parser.Lex(); // Eat shift-type operand;
 | 
			
		||||
  int RegNum = TryParseRegister();
 | 
			
		||||
  if (RegNum == -1)
 | 
			
		||||
    return Error(Parser.getTok().getLoc(), "register expected");
 | 
			
		||||
  Parser.Lex(); // Eat the operator.
 | 
			
		||||
 | 
			
		||||
  Operands.push_back(ARMOperand::CreateReg(RegNum,S, Parser.getTok().getLoc()));
 | 
			
		||||
  Operands.push_back(ARMOperand::CreateShifter(ShiftTy,
 | 
			
		||||
  // The source register for the shift has already been added to the
 | 
			
		||||
  // operand list, so we need to pop it off and combine it into the shifted
 | 
			
		||||
  // register operand instead.
 | 
			
		||||
  ARMOperand *PrevOp = (ARMOperand*)Operands.pop_back_val();
 | 
			
		||||
  if (!PrevOp->isReg())
 | 
			
		||||
    return Error(PrevOp->getStartLoc(), "shift must be of a register");
 | 
			
		||||
  int SrcReg = PrevOp->getReg();
 | 
			
		||||
  int64_t Imm = 0;
 | 
			
		||||
  int ShiftReg = 0;
 | 
			
		||||
  if (ShiftTy == ARM_AM::rrx) {
 | 
			
		||||
    // RRX Doesn't have an explicit shift amount. The encoder expects
 | 
			
		||||
    // the shift register to be the same as the source register. Seems odd,
 | 
			
		||||
    // but OK.
 | 
			
		||||
    ShiftReg = SrcReg;
 | 
			
		||||
  } else {
 | 
			
		||||
    // Figure out if this is shifted by a constant or a register (for non-RRX).
 | 
			
		||||
    if (Parser.getTok().is(AsmToken::Hash)) {
 | 
			
		||||
      Parser.Lex(); // Eat hash.
 | 
			
		||||
      SMLoc ImmLoc = Parser.getTok().getLoc();
 | 
			
		||||
      const MCExpr *ShiftExpr = 0;
 | 
			
		||||
      if (getParser().ParseExpression(ShiftExpr))
 | 
			
		||||
        return Error(ImmLoc, "invalid immediate shift value");
 | 
			
		||||
      // The expression must be evaluatable as an immediate.
 | 
			
		||||
      const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(ShiftExpr);
 | 
			
		||||
      if (!CE)
 | 
			
		||||
        return Error(ImmLoc, "invalid immediate shift value");
 | 
			
		||||
      // Range check the immediate.
 | 
			
		||||
      // lsl, ror: 0 <= imm <= 31
 | 
			
		||||
      // lsr, asr: 0 <= imm <= 32
 | 
			
		||||
      Imm = CE->getValue();
 | 
			
		||||
      if (Imm < 0 ||
 | 
			
		||||
          ((ShiftTy == ARM_AM::lsl || ShiftTy == ARM_AM::ror) && Imm > 31) ||
 | 
			
		||||
          ((ShiftTy == ARM_AM::lsr || ShiftTy == ARM_AM::asr) && Imm > 32)) {
 | 
			
		||||
        return Error(ImmLoc, "immediate shift value out of range");
 | 
			
		||||
      }
 | 
			
		||||
    } else if (Parser.getTok().is(AsmToken::Identifier)) {
 | 
			
		||||
      ShiftReg = TryParseRegister();
 | 
			
		||||
      SMLoc L = Parser.getTok().getLoc();
 | 
			
		||||
      if (ShiftReg == -1)
 | 
			
		||||
        return Error (L, "expected immediate or register in shift operand");
 | 
			
		||||
    } else
 | 
			
		||||
      return Error (Parser.getTok().getLoc(),
 | 
			
		||||
                    "expected immediate or register in shift operand");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  Operands.push_back(ARMOperand::CreateShiftedRegister(ShiftTy, SrcReg,
 | 
			
		||||
                                                       ShiftReg, Imm,
 | 
			
		||||
                                               S, Parser.getTok().getLoc()));
 | 
			
		||||
 | 
			
		||||
  return false;
 | 
			
		||||
 
 | 
			
		||||
@@ -142,6 +142,8 @@ void ARMInstPrinter::printSORegOperand(const MCInst *MI, unsigned OpNum,
 | 
			
		||||
  // Print the shift opc.
 | 
			
		||||
  ARM_AM::ShiftOpc ShOpc = ARM_AM::getSORegShOp(MO3.getImm());
 | 
			
		||||
  O << ", " << ARM_AM::getShiftOpcStr(ShOpc);
 | 
			
		||||
  if (ShOpc == ARM_AM::rrx)
 | 
			
		||||
    return;
 | 
			
		||||
  if (MO2.getReg()) {
 | 
			
		||||
    O << ' ' << getRegisterName(MO2.getReg());
 | 
			
		||||
    assert(ARM_AM::getSORegOffset(MO3.getImm()) == 0);
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user