[llvm-commits] [llvm] r138773 - in /llvm/trunk: include/llvm/MC/MCInstrDesc.h lib/CodeGen/MachineInstr.cpp lib/Target/ARM/AsmParser/ARMAsmParser.cpp test/MC/ARM/basic-thumb2-instructions.s test/MC/ARM/thumb2-diagnostics.s
Jim Grosbach
grosbach at apple.com
Mon Aug 29 15:24:09 PDT 2011
Author: grosbach
Date: Mon Aug 29 17:24:09 2011
New Revision: 138773
URL: http://llvm.org/viewvc/llvm-project?rev=138773&view=rev
Log:
Thumb2 parsing and encoding for IT blocks.
Added:
llvm/trunk/test/MC/ARM/basic-thumb2-instructions.s
llvm/trunk/test/MC/ARM/thumb2-diagnostics.s
Modified:
llvm/trunk/include/llvm/MC/MCInstrDesc.h
llvm/trunk/lib/CodeGen/MachineInstr.cpp
llvm/trunk/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
Modified: llvm/trunk/include/llvm/MC/MCInstrDesc.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/MC/MCInstrDesc.h?rev=138773&r1=138772&r2=138773&view=diff
==============================================================================
--- llvm/trunk/include/llvm/MC/MCInstrDesc.h (original)
+++ llvm/trunk/include/llvm/MC/MCInstrDesc.h Mon Aug 29 17:24:09 2011
@@ -289,6 +289,18 @@
return Flags & (1 << MCID::Barrier);
}
+ /// findFirstPredOperandIdx() - Find the index of the first operand in the
+ /// operand list that is used to represent the predicate. It returns -1 if
+ /// none is found.
+ int findFirstPredOperandIdx() const {
+ if (isPredicable()) {
+ for (unsigned i = 0, e = getNumOperands(); i != e; ++i)
+ if (OpInfo[i].isPredicate())
+ return i;
+ }
+ return -1;
+ }
+
/// isTerminator - Returns true if this instruction part of the terminator for
/// a basic block. Typically this is things like return and branch
/// instructions.
Modified: llvm/trunk/lib/CodeGen/MachineInstr.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/MachineInstr.cpp?rev=138773&r1=138772&r2=138773&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/MachineInstr.cpp (original)
+++ llvm/trunk/lib/CodeGen/MachineInstr.cpp Mon Aug 29 17:24:09 2011
@@ -942,6 +942,10 @@
/// operand list that is used to represent the predicate. It returns -1 if
/// none is found.
int MachineInstr::findFirstPredOperandIdx() const {
+ // Don't call MCID.findFirstPredOperandIdx() because this variant
+ // is sometimes called on an instruction that's not yet complete, and
+ // so the number of operands is less than the MCID indicates. In
+ // particular, the PTX target does this.
const MCInstrDesc &MCID = getDesc();
if (MCID.isPredicable()) {
for (unsigned i = 0, e = getNumOperands(); i != e; ++i)
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=138773&r1=138772&r2=138773&view=diff
==============================================================================
--- llvm/trunk/lib/Target/ARM/AsmParser/ARMAsmParser.cpp (original)
+++ llvm/trunk/lib/Target/ARM/AsmParser/ARMAsmParser.cpp Mon Aug 29 17:24:09 2011
@@ -44,6 +44,28 @@
MCSubtargetInfo &STI;
MCAsmParser &Parser;
+ struct {
+ ARMCC::CondCodes Cond; // Condition for IT block.
+ unsigned Mask:4; // Condition mask for instructions.
+ // Starting at first 1 (from lsb).
+ // '1' condition as indicated in IT.
+ // '0' inverse of condition (else).
+ // Count of instructions in IT block is
+ // 4 - trailingzeroes(mask)
+
+ bool FirstCond; // Explicit flag for when we're parsing the
+ // First instruction in the IT block. It's
+ // implied in the mask, so needs special
+ // handling.
+
+ unsigned CurPosition; // Current position in parsing of IT
+ // block. In range [0,3]. Initialized
+ // according to count of instructions in block.
+ // ~0U if no active IT block.
+ } ITState;
+ bool inITBlock() { return ITState.CurPosition != ~0U;}
+
+
MCAsmParser &getParser() const { return Parser; }
MCAsmLexer &getLexer() const { return Parser.getLexer(); }
@@ -165,6 +187,7 @@
public:
enum ARMMatchResultTy {
Match_RequiresITBlock = FIRST_TARGET_MATCH_RESULT_TY,
+ Match_RequiresNotITBlock,
Match_RequiresV6,
Match_RequiresThumb2
};
@@ -175,6 +198,9 @@
// Initialize the set of available features.
setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits()));
+
+ // Not in an ITBlock to start with.
+ ITState.CurPosition = ~0U;
}
// Implementation of the MCTargetAsmParser interface:
@@ -3085,18 +3111,23 @@
// where the conditional bit0 is zero, the instruction post-processing
// will adjust the mask accordingly.
if (Mnemonic == "it") {
+ SMLoc Loc = SMLoc::getFromPointer(NameLoc.getPointer() + 2);
+ if (ITMask.size() > 3) {
+ Parser.EatToEndOfStatement();
+ return Error(Loc, "too many conditions on IT instruction");
+ }
unsigned Mask = 8;
for (unsigned i = ITMask.size(); i != 0; --i) {
char pos = ITMask[i - 1];
if (pos != 't' && pos != 'e') {
Parser.EatToEndOfStatement();
- return Error(NameLoc, "illegal IT instruction mask '" + ITMask + "'");
+ return Error(Loc, "illegal IT block condition mask '" + ITMask + "'");
}
Mask >>= 1;
if (ITMask[i - 1] == 't')
Mask |= 8;
}
- Operands.push_back(ARMOperand::CreateITMask(Mask, NameLoc));
+ Operands.push_back(ARMOperand::CreateITMask(Mask, Loc));
}
// FIXME: This is all a pretty gross hack. We should automatically handle
@@ -3128,18 +3159,18 @@
}
// Add the carry setting operand, if necessary.
- //
- // FIXME: It would be awesome if we could somehow invent a location such that
- // match errors on this operand would print a nice diagnostic about how the
- // 's' character in the mnemonic resulted in a CCOut operand.
- if (CanAcceptCarrySet)
+ if (CanAcceptCarrySet) {
+ SMLoc Loc = SMLoc::getFromPointer(NameLoc.getPointer() + Mnemonic.size());
Operands.push_back(ARMOperand::CreateCCOut(CarrySetting ? ARM::CPSR : 0,
- NameLoc));
+ Loc));
+ }
// Add the predication code operand, if necessary.
if (CanAcceptPredicationCode) {
+ SMLoc Loc = SMLoc::getFromPointer(NameLoc.getPointer() + Mnemonic.size() +
+ CarrySetting);
Operands.push_back(ARMOperand::CreateCondCode(
- ARMCC::CondCodes(PredicationCode), NameLoc));
+ ARMCC::CondCodes(PredicationCode), Loc));
}
// Add the processor imod operand, if necessary.
@@ -3261,10 +3292,57 @@
return false;
}
+// FIXME: We would really prefer to have MCInstrInfo (the wrapper around
+// the ARMInsts array) instead. Getting that here requires awkward
+// API changes, though. Better way?
+namespace llvm {
+extern MCInstrDesc ARMInsts[];
+}
+static MCInstrDesc &getInstDesc(unsigned Opcode) {
+ return ARMInsts[Opcode];
+}
+
// FIXME: We would really like to be able to tablegen'erate this.
bool ARMAsmParser::
validateInstruction(MCInst &Inst,
const SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
+ MCInstrDesc &MCID = getInstDesc(Inst.getOpcode());
+ SMLoc Loc = Operands[0]->getStartLoc();
+ // Check the IT block state first.
+ if (inITBlock()) {
+ unsigned bit = 1;
+ if (ITState.FirstCond)
+ ITState.FirstCond = false;
+ else
+ bit = (ITState.Mask >> (4 - ITState.CurPosition)) & 1;
+ // Increment our position in the IT block first thing, as we want to
+ // move forward even if we find an error in the IT block.
+ unsigned TZ = CountTrailingZeros_32(ITState.Mask);
+ if (++ITState.CurPosition == 4 - TZ)
+ ITState.CurPosition = ~0U; // Done with the IT block after this.
+ // The instruction must be predicable.
+ if (!MCID.isPredicable())
+ return Error(Loc, "instructions in IT block must be predicable");
+ unsigned Cond = Inst.getOperand(MCID.findFirstPredOperandIdx()).getImm();
+ unsigned ITCond = bit ? ITState.Cond :
+ ARMCC::getOppositeCondition(ITState.Cond);
+ if (Cond != ITCond) {
+ // Find the condition code Operand to get its SMLoc information.
+ SMLoc CondLoc;
+ for (unsigned i = 1; i < Operands.size(); ++i)
+ if (static_cast<ARMOperand*>(Operands[i])->isCondCode())
+ CondLoc = Operands[i]->getStartLoc();
+ return Error(CondLoc, "incorrect condition in IT block; got '" +
+ StringRef(ARMCondCodeToString(ARMCC::CondCodes(Cond))) +
+ "', but expected '" +
+ ARMCondCodeToString(ARMCC::CondCodes(ITCond)) + "'");
+ }
+ // Check for non-'al' condition codes outside of the IT block.
+ } else if (isThumbTwo() && MCID.isPredicable() &&
+ Inst.getOperand(MCID.findFirstPredOperandIdx()).getImm() !=
+ ARMCC::AL)
+ return Error(Loc, "predicated instructions must be in IT block");
+
switch (Inst.getOpcode()) {
case ARM::LDRD:
case ARM::LDRD_PRE:
@@ -3413,29 +3491,28 @@
// so mask that in if needed
MCOperand &MO = Inst.getOperand(1);
unsigned Mask = MO.getImm();
+ unsigned OrigMask = Mask;
+ unsigned TZ = CountTrailingZeros_32(Mask);
if ((Inst.getOperand(0).getImm() & 1) == 0) {
- unsigned TZ = CountTrailingZeros_32(Mask);
assert(Mask && TZ <= 3 && "illegal IT mask value!");
for (unsigned i = 3; i != TZ; --i)
Mask ^= 1 << i;
} else
Mask |= 0x10;
MO.setImm(Mask);
+
+ // Set up the IT block state according to the IT instruction we just
+ // matched.
+ assert(!inITBlock() && "nested IT blocks?!");
+ ITState.Cond = ARMCC::CondCodes(Inst.getOperand(0).getImm());
+ ITState.Mask = OrigMask; // Use the original mask, not the updated one.
+ ITState.CurPosition = 0;
+ ITState.FirstCond = true;
break;
}
}
}
-// FIXME: We would really prefer to have MCInstrInfo (the wrapper around
-// the ARMInsts array) instead. Getting that here requires awkward
-// API changes, though. Better way?
-namespace llvm {
-extern MCInstrDesc ARMInsts[];
-}
-static MCInstrDesc &getInstDesc(unsigned Opcode) {
- return ARMInsts[Opcode];
-}
-
unsigned ARMAsmParser::checkTargetMatchPredicate(MCInst &Inst) {
// 16-bit thumb arithmetic instructions either require or preclude the 'S'
// suffix depending on whether they're in an IT block or not.
@@ -3457,10 +3534,12 @@
return Match_MnemonicFail;
// If we're parsing Thumb2, which form is legal depends on whether we're
// in an IT block.
- // FIXME: We don't yet do IT blocks, so just always consider it to be
- // that we aren't in one until we do.
- if (isThumbTwo() && Inst.getOperand(OpNo).getReg() != ARM::CPSR)
+ if (isThumbTwo() && Inst.getOperand(OpNo).getReg() != ARM::CPSR &&
+ !inITBlock())
return Match_RequiresITBlock;
+ if (isThumbTwo() && Inst.getOperand(OpNo).getReg() == ARM::CPSR &&
+ inITBlock())
+ return Match_RequiresNotITBlock;
}
// Some high-register supporting Thumb1 encodings only allow both registers
// to be from r0-r7 when in Thumb2.
@@ -3518,6 +3597,8 @@
case Match_ConversionFail:
// The converter function will have already emited a diagnostic.
return true;
+ case Match_RequiresNotITBlock:
+ return Error(IDLoc, "flag setting instruction only valid outside IT block");
case Match_RequiresITBlock:
return Error(IDLoc, "instruction only valid inside IT block");
case Match_RequiresV6:
Added: llvm/trunk/test/MC/ARM/basic-thumb2-instructions.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/ARM/basic-thumb2-instructions.s?rev=138773&view=auto
==============================================================================
--- llvm/trunk/test/MC/ARM/basic-thumb2-instructions.s (added)
+++ llvm/trunk/test/MC/ARM/basic-thumb2-instructions.s Mon Aug 29 17:24:09 2011
@@ -0,0 +1,32 @@
+@ RUN: llvm-mc -triple=thumbv7-apple-darwin -show-encoding < %s | FileCheck %s
+ .syntax unified
+ .globl _func
+
+@ Check that the assembler can handle the documented syntax from the ARM ARM.
+@ For complex constructs like shifter operands, check more thoroughly for them
+@ once then spot check that following instructions accept the form generally.
+@ This gives us good coverage while keeping the overall size of the test
+@ more reasonable.
+
+
+@ FIXME: Some 3-operand instructions have a 2-operand assembly syntax.
+
+_func:
+@ CHECK: _func
+
+ at ------------------------------------------------------------------------------
+@ IT
+ at ------------------------------------------------------------------------------
+@ Test encodings of a few full IT blocks, not just the IT instruction
+
+ iteet eq
+ addeq r0, r1, r2
+ nopne
+ subne r5, r6, r7
+ addeq r1, r2, #4
+
+@ CHECK: iteet eq @ encoding: [0x0d,0xbf]
+@ CHECK: addeq r0, r1, r2 @ encoding: [0x88,0x18]
+@ CHECK: nopne @ encoding: [0x00,0xbf]
+@ CHECK: subne r5, r6, r7 @ encoding: [0xf5,0x1b]
+@ CHECK: addeq r1, r2, #4 @ encoding: [0x11,0x1d]
Added: llvm/trunk/test/MC/ARM/thumb2-diagnostics.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/ARM/thumb2-diagnostics.s?rev=138773&view=auto
==============================================================================
--- llvm/trunk/test/MC/ARM/thumb2-diagnostics.s (added)
+++ llvm/trunk/test/MC/ARM/thumb2-diagnostics.s Mon Aug 29 17:24:09 2011
@@ -0,0 +1,30 @@
+@ RUN: not llvm-mc -triple=thumbv7-apple-darwin < %s 2> %t
+@ RUN: FileCheck --check-prefix=CHECK-ERRORS < %t %s
+
+@ Ill-formed IT block instructions.
+ itet eq
+ addle r0, r1, r2
+ nop
+ it le
+ iteeee gt
+ ittfe le
+ nopeq
+
+@ CHECK-ERRORS: error: incorrect condition in IT block; got 'le', but expected 'eq'
+@ CHECK-ERRORS: addle r0, r1, r2
+@ CHECK-ERRORS: ^
+@ CHECK-ERRORS: error: incorrect condition in IT block; got 'al', but expected 'ne'
+@ CHECK-ERRORS: nop
+@ CHECK-ERRORS: ^
+@ CHECK-ERRORS: error: instructions in IT block must be predicable
+@ CHECK-ERRORS: it le
+@ CHECK-ERRORS: ^
+@ CHECK-ERRORS: error: too many conditions on IT instruction
+@ CHECK-ERRORS: iteeee gt
+@ CHECK-ERRORS: ^
+@ CHECK-ERRORS: error: illegal IT block condition mask 'tfe'
+@ CHECK-ERRORS: ittfe le
+@ CHECK-ERRORS: ^
+@ CHECK-ERRORS: error: predicated instructions must be in IT block
+@ CHECK-ERRORS: nopeq
+@ CHECK-ERRORS: ^
More information about the llvm-commits
mailing list