diff options
-rw-r--r-- | lib/Target/ARM/ARMInstrInfo.td | 5 | ||||
-rw-r--r-- | lib/Target/ARM/AsmParser/ARMAsmParser.cpp | 101 | ||||
-rw-r--r-- | test/MC/ARM/basic-arm-instructions.s | 26 |
3 files changed, 130 insertions, 2 deletions
diff --git a/lib/Target/ARM/ARMInstrInfo.td b/lib/Target/ARM/ARMInstrInfo.td index e756616157..fec5f72bcf 100644 --- a/lib/Target/ARM/ARMInstrInfo.td +++ b/lib/Target/ARM/ARMInstrInfo.td @@ -536,12 +536,17 @@ def imm24b : Operand<i32>, ImmLeaf<i32, [{ /// bf_inv_mask_imm predicate - An AND mask to clear an arbitrary width bitfield /// e.g., 0xf000ffff +def BitfieldAsmOperand : AsmOperandClass { + let Name = "Bitfield"; + let ParserMethod = "parseBitfield"; +} def bf_inv_mask_imm : Operand<i32>, PatLeaf<(imm), [{ return ARM::isBitFieldInvertedMask(N->getZExtValue()); }] > { let EncoderMethod = "getBitfieldInvertedMaskOpValue"; let PrintMethod = "printBitfieldInvMaskImmOperand"; + let ParserMatchClass = BitfieldAsmOperand; } /// lsb_pos_imm - position of the lsb bit, used by BFI4p and t2BFI4p diff --git a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp index bbeec1cac4..a528572349 100644 --- a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -125,6 +125,7 @@ class ARMAsmParser : public MCTargetAsmParser { OperandMatchResultTy parseSetEndImm(SmallVectorImpl<MCParsedAsmOperand*>&); OperandMatchResultTy parseShifterImm(SmallVectorImpl<MCParsedAsmOperand*>&); OperandMatchResultTy parseRotImm(SmallVectorImpl<MCParsedAsmOperand*>&); + OperandMatchResultTy parseBitfield(SmallVectorImpl<MCParsedAsmOperand*>&); // Asm Match Converter Methods bool cvtLdWriteBackRegAddrMode2(MCInst &Inst, unsigned Opcode, @@ -184,6 +185,7 @@ class ARMOperand : public MCParsedAsmOperand { ShiftedImmediate, ShifterImmediate, RotateImmediate, + BitfieldDescriptor, Token } Kind; @@ -260,6 +262,10 @@ class ARMOperand : public MCParsedAsmOperand { struct { unsigned Imm; } RotImm; + struct { + unsigned LSB; + unsigned Width; + } Bitfield; }; ARMOperand(KindTy K) : MCParsedAsmOperand(), Kind(K) {} @@ -315,6 +321,9 @@ public: case RotateImmediate: RotImm = o.RotImm; break; + case BitfieldDescriptor: + Bitfield = o.Bitfield; + break; } } @@ -535,6 +544,7 @@ public: bool isRegShiftedReg() const { return Kind == ShiftedRegister; } bool isRegShiftedImm() const { return Kind == ShiftedImmediate; } bool isRotImm() const { return Kind == RotateImmediate; } + bool isBitfield() const { return Kind == BitfieldDescriptor; } bool isMemMode2() const { if (getMemAddrMode() != ARMII::AddrMode2) return false; @@ -711,6 +721,17 @@ public: Inst.addOperand(MCOperand::CreateImm(RotImm.Imm >> 3)); } + void addBitfieldOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + // Munge the lsb/width into a bitfield mask. + unsigned lsb = Bitfield.LSB; + unsigned width = Bitfield.Width; + // Make a 32-bit mask w/ the referenced bits clear and all other bits set. + uint32_t Mask = ~(((uint32_t)0xffffffff >> lsb) << (32 - width) >> + (32 - (lsb + width))); + Inst.addOperand(MCOperand::CreateImm(Mask)); + } + void addImmOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); addExpr(Inst, getImm()); @@ -1026,6 +1047,16 @@ public: return Op; } + static ARMOperand *CreateBitfield(unsigned LSB, unsigned Width, + SMLoc S, SMLoc E) { + ARMOperand *Op = new ARMOperand(BitfieldDescriptor); + Op->Bitfield.LSB = LSB; + Op->Bitfield.Width = Width; + Op->StartLoc = S; + Op->EndLoc = E; + return Op; + } + static ARMOperand * CreateRegList(const SmallVectorImpl<std::pair<unsigned, SMLoc> > &Regs, SMLoc StartLoc, SMLoc EndLoc) { @@ -1204,6 +1235,10 @@ void ARMOperand::print(raw_ostream &OS) const { case RotateImmediate: OS << "<ror " << " #" << (RotImm.Imm * 8) << ">"; break; + case BitfieldDescriptor: + OS << "<bitfield " << "lsb: " << Bitfield.LSB + << ", width: " << Bitfield.Width << ">"; + break; case RegisterList: case DPRRegisterList: case SPRRegisterList: { @@ -1883,6 +1918,72 @@ parseRotImm(SmallVectorImpl<MCParsedAsmOperand*> &Operands) { return MatchOperand_Success; } +ARMAsmParser::OperandMatchResultTy ARMAsmParser:: +parseBitfield(SmallVectorImpl<MCParsedAsmOperand*> &Operands) { + SMLoc S = Parser.getTok().getLoc(); + // The bitfield descriptor is really two operands, the LSB and the width. + if (Parser.getTok().isNot(AsmToken::Hash)) { + Error(Parser.getTok().getLoc(), "'#' expected"); + return MatchOperand_ParseFail; + } + Parser.Lex(); // Eat hash token. + + const MCExpr *LSBExpr; + SMLoc E = Parser.getTok().getLoc(); + if (getParser().ParseExpression(LSBExpr)) { + Error(E, "malformed immediate expression"); + return MatchOperand_ParseFail; + } + const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(LSBExpr); + if (!CE) { + Error(E, "'lsb' operand must be an immediate"); + return MatchOperand_ParseFail; + } + + int64_t LSB = CE->getValue(); + // The LSB must be in the range [0,31] + if (LSB < 0 || LSB > 31) { + Error(E, "'lsb' operand must be in the range [0,31]"); + return MatchOperand_ParseFail; + } + E = Parser.getTok().getLoc(); + + // Expect another immediate operand. + if (Parser.getTok().isNot(AsmToken::Comma)) { + Error(Parser.getTok().getLoc(), "too few operands"); + return MatchOperand_ParseFail; + } + Parser.Lex(); // Eat hash token. + if (Parser.getTok().isNot(AsmToken::Hash)) { + Error(Parser.getTok().getLoc(), "'#' expected"); + return MatchOperand_ParseFail; + } + Parser.Lex(); // Eat hash token. + + const MCExpr *WidthExpr; + if (getParser().ParseExpression(WidthExpr)) { + Error(E, "malformed immediate expression"); + return MatchOperand_ParseFail; + } + CE = dyn_cast<MCConstantExpr>(WidthExpr); + if (!CE) { + Error(E, "'width' operand must be an immediate"); + return MatchOperand_ParseFail; + } + + int64_t Width = CE->getValue(); + // The LSB must be in the range [1,32-lsb] + if (Width < 1 || Width > 32 - LSB) { + Error(E, "'width' operand must be in the range [1,32-lsb]"); + return MatchOperand_ParseFail; + } + E = Parser.getTok().getLoc(); + + Operands.push_back(ARMOperand::CreateBitfield(LSB, Width, 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/test/MC/ARM/basic-arm-instructions.s b/test/MC/ARM/basic-arm-instructions.s index 1c33a73d14..2903c8d35c 100644 --- a/test/MC/ARM/basic-arm-instructions.s +++ b/test/MC/ARM/basic-arm-instructions.s @@ -258,12 +258,34 @@ Lforward: @------------------------------------------------------------------------------ @ FIXME: B @------------------------------------------------------------------------------ + b _bar + beq _baz + +@ CHECK: b _bar @ encoding: [A,A,A,0xea] + @ fixup A - offset: 0, value: _bar, kind: fixup_arm_uncondbranch +@ CHECK: beq _baz @ encoding: [A,A,A,0x0a] + @ fixup A - offset: 0, value: _baz, kind: fixup_arm_condbranch + + @------------------------------------------------------------------------------ -@ FIXME: BFC +@ BFC @------------------------------------------------------------------------------ + bfc r5, #3, #17 + bfccc r5, #3, #17 + +@ CHECK: bfc r5, #3, #17 @ encoding: [0x9f,0x51,0xd3,0xe7] +@ CHECK: bfclo r5, #3, #17 @ encoding: [0x9f,0x51,0xd3,0x37] + + @------------------------------------------------------------------------------ -@ FIXME: BFI +@ BFI @------------------------------------------------------------------------------ + bfi r5, r2, #3, #17 + bfine r5, r2, #3, #17 + +@ CHECK: bfi r5, r2, #3, #17 @ encoding: [0x92,0x51,0xd3,0xe7] +@ CHECK: bfine r5, r2, #3, #17 @ encoding: [0x92,0x51,0xd3,0x17] + @------------------------------------------------------------------------------ @ BIC |