#include "llvm/Support/ARMBuildAttributes.h"
#include "llvm/Support/ARMEHABI.h"
#include "llvm/Support/COFF.h"
+#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ELF.h"
#include "llvm/Support/MathExtras.h"
namespace {
+enum class ImplicitItModeTy { Always, Never, ARMOnly, ThumbOnly };
+
+static cl::opt<ImplicitItModeTy> ImplicitItMode(
+ "arm-implicit-it", cl::init(ImplicitItModeTy::ARMOnly),
+ cl::desc("Allow conditional instructions outdside of an IT block"),
+ cl::values(clEnumValN(ImplicitItModeTy::Always, "always",
+ "Accept in both ISAs, emit implicit ITs in Thumb"),
+ clEnumValN(ImplicitItModeTy::Never, "never",
+ "Warn in ARM, reject in Thumb"),
+ clEnumValN(ImplicitItModeTy::ARMOnly, "arm",
+ "Accept in ARM, reject in Thumb"),
+ clEnumValN(ImplicitItModeTy::ThumbOnly, "thumb",
+ "Warn in ARM, emit implicit ITs in Thumb"),
+ clEnumValEnd));
+
class ARMOperand;
enum VectorLaneTy { NoLanes, AllLanes, IndexedLane };
bool NextSymbolIsThumb;
+ bool useImplicitITThumb() const {
+ return ImplicitItMode == ImplicitItModeTy::Always ||
+ ImplicitItMode == ImplicitItModeTy::ThumbOnly;
+ }
+
+ bool useImplicitITARM() const {
+ return ImplicitItMode == ImplicitItModeTy::Always ||
+ ImplicitItMode == ImplicitItModeTy::ARMOnly;
+ }
+
struct {
ARMCC::CondCodes Cond; // Condition for IT block.
unsigned Mask:4; // Condition mask for instructions.
// '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.
+ // Note that this does not have the same encoding
+ // as in the IT instruction, which also depends
+ // on the low bit of the condition code.
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.
+ // block. In range [0,4], with 0 being the IT
+ // instruction itself. Initialized according to
+ // count of instructions in block. ~0U if no
+ // active IT block.
+
+ bool IsExplicit; // true - The IT instruction was present in the
+ // input, we should not modify it.
+ // false - The IT instruction was added
+ // implicitly, we can extend it if that
+ // would be legal.
} ITState;
+
+ llvm::SmallVector<MCInst, 4> PendingConditionalInsts;
+
+ void flushPendingInstructions(MCStreamer &Out) override {
+ if (!inImplicitITBlock()) {
+ assert(PendingConditionalInsts.size() == 0);
+ return;
+ }
+
+ // Emit the IT instruction
+ unsigned Mask = getITMaskEncoding();
+ MCInst ITInst;
+ ITInst.setOpcode(ARM::t2IT);
+ ITInst.addOperand(MCOperand::createImm(ITState.Cond));
+ ITInst.addOperand(MCOperand::createImm(Mask));
+ Out.EmitInstruction(ITInst, getSTI());
+
+ // Emit the conditonal instructions
+ assert(PendingConditionalInsts.size() <= 4);
+ for (MCInst Inst : PendingConditionalInsts) {
+ Out.EmitInstruction(Inst, getSTI());
+ }
+ PendingConditionalInsts.clear();
+
+ // Clear the IT state
+ ITState.Mask = 0;
+ ITState.CurPosition = ~0U;
+ }
+
bool inITBlock() { return ITState.CurPosition != ~0U; }
+ bool inExplicitITBlock() { return inITBlock() && ITState.IsExplicit; }
+ bool inImplicitITBlock() { return inITBlock() && !ITState.IsExplicit; }
bool lastInITBlock() {
return ITState.CurPosition == 4 - countTrailingZeros(ITState.Mask);
}
void forwardITPosition() {
if (!inITBlock()) return;
// Move to the next instruction in the IT block, if there is one. If not,
- // mark the block as done.
+ // mark the block as done, except for implicit IT blocks, which we leave
+ // open until we find an instruction that can't be added to it.
unsigned TZ = countTrailingZeros(ITState.Mask);
- if (++ITState.CurPosition == 5 - TZ)
+ if (++ITState.CurPosition == 5 - TZ && ITState.IsExplicit)
ITState.CurPosition = ~0U; // Done with the IT block after this.
}
+ // Rewind the state of the current IT block, removing the last slot from it.
+ void rewindImplicitITPosition() {
+ assert(inImplicitITBlock());
+ assert(ITState.CurPosition > 1);
+ ITState.CurPosition--;
+ unsigned TZ = countTrailingZeros(ITState.Mask);
+ unsigned NewMask = 0;
+ NewMask |= ITState.Mask & (0xC << TZ);
+ NewMask |= 0x2 << TZ;
+ ITState.Mask = NewMask;
+ }
+
+ // Rewind the state of the current IT block, removing the last slot from it.
+ // If we were at the first slot, this closes the IT block.
+ void discardImplicitITBlock() {
+ assert(inImplicitITBlock());
+ assert(ITState.CurPosition == 1);
+ ITState.CurPosition = ~0U;
+ return;
+ }
+
+ // Get the encoding of the IT mask, as it will appear in an IT instruction.
+ unsigned getITMaskEncoding() {
+ assert(inITBlock());
+ unsigned Mask = ITState.Mask;
+ unsigned TZ = countTrailingZeros(Mask);
+ if ((ITState.Cond & 1) == 0) {
+ assert(Mask && TZ <= 3 && "illegal IT mask value!");
+ Mask ^= (0xE << TZ) & 0xF;
+ }
+ return Mask;
+ }
+
+ // Get the condition code corresponding to the current IT block slot.
+ ARMCC::CondCodes currentITCond() {
+ unsigned MaskBit;
+ if (ITState.CurPosition == 1)
+ MaskBit = 1;
+ else
+ MaskBit = (ITState.Mask >> (5 - ITState.CurPosition)) & 1;
+
+ return MaskBit ? ITState.Cond : ARMCC::getOppositeCondition(ITState.Cond);
+ }
+
+ // Invert the condition of the current IT block slot without changing any
+ // other slots in the same block.
+ void invertCurrentITCondition() {
+ if (ITState.CurPosition == 1) {
+ ITState.Cond = ARMCC::getOppositeCondition(ITState.Cond);
+ } else {
+ ITState.Mask ^= 1 << (5 - ITState.CurPosition);
+ }
+ }
+
+ // Returns true if the current IT block is full (all 4 slots used).
+ bool isITBlockFull() {
+ return inITBlock() && (ITState.Mask & 1);
+ }
+
+ // Extend the current implicit IT block to have one more slot with the given
+ // condition code.
+ void extendImplicitITBlock(ARMCC::CondCodes Cond) {
+ assert(inImplicitITBlock());
+ assert(!isITBlockFull());
+ assert(Cond == ITState.Cond ||
+ Cond == ARMCC::getOppositeCondition(ITState.Cond));
+ unsigned TZ = countTrailingZeros(ITState.Mask);
+ unsigned NewMask = 0;
+ // Keep any existing condition bits.
+ NewMask |= ITState.Mask & (0xE << TZ);
+ // Insert the new condition bit.
+ NewMask |= (Cond == ITState.Cond) << TZ;
+ // Move the trailing 1 down one bit.
+ NewMask |= 1 << (TZ - 1);
+ ITState.Mask = NewMask;
+ }
+
+ // Create a new implicit IT block with a dummy condition code.
+ void startImplicitITBlock() {
+ assert(!inITBlock());
+ ITState.Cond = ARMCC::AL;
+ ITState.Mask = 8;
+ ITState.CurPosition = 1;
+ ITState.IsExplicit = false;
+ return;
+ }
+
+ // Create a new explicit IT block with the given condition and mask. The mask
+ // should be in the parsed format, with a 1 implying 't', regardless of the
+ // low bit of the condition.
+ void startExplicitITBlock(ARMCC::CondCodes Cond, unsigned Mask) {
+ assert(!inITBlock());
+ ITState.Cond = Cond;
+ ITState.Mask = Mask;
+ ITState.CurPosition = 0;
+ ITState.IsExplicit = true;
+ return;
+ }
+
void Note(SMLoc L, const Twine &Msg, ArrayRef<SMRange> Ranges = None) {
return getParser().Note(L, Msg, Ranges);
}
bool processInstruction(MCInst &Inst, const OperandVector &Ops, MCStreamer &Out);
bool shouldOmitCCOutOperand(StringRef Mnemonic, OperandVector &Operands);
bool shouldOmitPredicateOperand(StringRef Mnemonic, OperandVector &Operands);
+ bool isITBlockTerminator(MCInst &Inst) const;
public:
enum ARMMatchResultTy {
OperandVector &Operands, MCStreamer &Out,
uint64_t &ErrorInfo,
bool MatchingInlineAsm) override;
+ unsigned MatchInstruction(OperandVector &Operands, MCInst &Inst,
+ uint64_t &ErrorInfo, bool MatchingInlineAsm,
+ bool &EmitInITBlock, MCStreamer &Out);
void onLabelParsed(MCSymbol *Symbol) override;
};
} // end anonymous namespace
// NOTE: BKPT and HLT instructions have the interesting property of being
// allowed in IT blocks, but not being predicable. They just always execute.
if (inITBlock() && !instIsBreakpoint(Inst)) {
- unsigned Bit = 1;
- if (ITState.FirstCond)
- ITState.FirstCond = false;
- else
- Bit = (ITState.Mask >> (5 - ITState.CurPosition)) & 1;
// 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) {
+ if (Cond != currentITCond()) {
// Find the condition code Operand to get its SMLoc information.
SMLoc CondLoc;
for (unsigned I = 1; I < Operands.size(); ++I)
return Error(CondLoc, "incorrect condition in IT block; got '" +
StringRef(ARMCondCodeToString(ARMCC::CondCodes(Cond))) +
"', but expected '" +
- ARMCondCodeToString(ARMCC::CondCodes(ITCond)) + "'");
+ ARMCondCodeToString(ARMCC::CondCodes(currentITCond())) + "'");
}
// Check for non-'al' condition codes outside of the IT block.
} else if (isThumbTwo() && MCID.isPredicable() &&
Inst.getOperand(MCID.findFirstPredOperandIdx()).getImm() !=
ARMCC::AL && Inst.getOpcode() != ARM::tBcc &&
- Inst.getOpcode() != ARM::t2Bcc)
+ Inst.getOpcode() != ARM::t2Bcc) {
return Error(Loc, "predicated instructions must be in IT block");
+ } else if (!isThumb() && !useImplicitITARM() && MCID.isPredicable() &&
+ Inst.getOperand(MCID.findFirstPredOperandIdx()).getImm() !=
+ ARMCC::AL) {
+ return Warning(Loc, "predicated instructions should be in IT block");
+ }
const unsigned Opcode = Inst.getOpcode();
switch (Opcode) {
}
case ARM::ITasm:
case ARM::t2IT: {
- // The mask bits for all but the first condition are represented as
- // the low bit of the condition code value implies 't'. We currently
- // always have 1 implies 't', so XOR toggle the bits if the low bit
- // of the condition code is zero.
MCOperand &MO = Inst.getOperand(1);
unsigned Mask = MO.getImm();
- unsigned OrigMask = Mask;
- unsigned TZ = countTrailingZeros(Mask);
- if ((Inst.getOperand(0).getImm() & 1) == 0) {
- assert(Mask && TZ <= 3 && "illegal IT mask value!");
- Mask ^= (0xE << TZ) & 0xF;
- }
- MO.setImm(Mask);
+ ARMCC::CondCodes Cond = ARMCC::CondCodes(Inst.getOperand(0).getImm());
// 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;
+ startExplicitITBlock(Cond, Mask);
+ MO.setImm(getITMaskEncoding());
break;
}
case ARM::t2LSLrr:
}
}
+// Returns true if Inst is unpredictable if it is in and IT block, but is not
+// the last instruction in the block.
+bool ARMAsmParser::isITBlockTerminator(MCInst &Inst) const {
+ const MCInstrDesc &MCID = MII.get(Inst.getOpcode());
+
+ // All branch & call instructions terminate IT blocks.
+ if (MCID.isTerminator() || MCID.isCall() || MCID.isReturn() ||
+ MCID.isBranch() || MCID.isIndirectBranch())
+ return true;
+
+ // Any arithmetic instruction which writes to the PC also terminates the IT
+ // block.
+ for (unsigned OpIdx = 0; OpIdx < MCID.getNumDefs(); ++OpIdx) {
+ MCOperand &Op = Inst.getOperand(OpIdx);
+ if (Op.isReg() && Op.getReg() == ARM::PC)
+ return true;
+ }
+
+ if (MCID.hasImplicitDefOfPhysReg(ARM::PC, MRI))
+ return true;
+
+ // Instructions with variable operand lists, which write to the variable
+ // operands. We only care about Thumb instructions here, as ARM instructions
+ // obviously can't be in an IT block.
+ switch (Inst.getOpcode()) {
+ case ARM::t2LDMIA:
+ case ARM::t2LDMIA_UPD:
+ case ARM::t2LDMDB:
+ case ARM::t2LDMDB_UPD:
+ if (listContainsReg(Inst, 3, ARM::PC))
+ return true;
+ break;
+ case ARM::tPOP:
+ if (listContainsReg(Inst, 2, ARM::PC))
+ return true;
+ break;
+ }
+
+ return false;
+}
+
+unsigned ARMAsmParser::MatchInstruction(OperandVector &Operands, MCInst &Inst,
+ uint64_t &ErrorInfo,
+ bool MatchingInlineAsm,
+ bool &EmitInITBlock,
+ MCStreamer &Out) {
+ // If we can't use an implicit IT block here, just match as normal.
+ if (inExplicitITBlock() || !isThumbTwo() || !useImplicitITThumb())
+ return MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm);
+
+ // Try to match the instruction in an extension of the current IT block (if
+ // there is one).
+ if (inImplicitITBlock()) {
+ extendImplicitITBlock(ITState.Cond);
+ if (MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm) ==
+ Match_Success) {
+ // The match succeded, but we still have to check that the instruction is
+ // valid in this implicit IT block.
+ const MCInstrDesc &MCID = MII.get(Inst.getOpcode());
+ if (MCID.isPredicable()) {
+ ARMCC::CondCodes InstCond =
+ (ARMCC::CondCodes)Inst.getOperand(MCID.findFirstPredOperandIdx())
+ .getImm();
+ ARMCC::CondCodes ITCond = currentITCond();
+ if (InstCond == ITCond) {
+ EmitInITBlock = true;
+ return Match_Success;
+ } else if (InstCond == ARMCC::getOppositeCondition(ITCond)) {
+ invertCurrentITCondition();
+ EmitInITBlock = true;
+ return Match_Success;
+ }
+ }
+ }
+ rewindImplicitITPosition();
+ }
+
+ // Finish the current IT block, and try to match outside any IT block.
+ flushPendingInstructions(Out);
+ unsigned PlainMatchResult =
+ MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm);
+ if (PlainMatchResult == Match_Success) {
+ const MCInstrDesc &MCID = MII.get(Inst.getOpcode());
+ if (MCID.isPredicable()) {
+ ARMCC::CondCodes InstCond =
+ (ARMCC::CondCodes)Inst.getOperand(MCID.findFirstPredOperandIdx())
+ .getImm();
+ // Some forms of the branch instruction have their own condition code
+ // fields, so can be conditionally executed without an IT block.
+ if (Inst.getOpcode() == ARM::tBcc || Inst.getOpcode() == ARM::t2Bcc) {
+ EmitInITBlock = false;
+ return Match_Success;
+ }
+ if (InstCond == ARMCC::AL) {
+ EmitInITBlock = false;
+ return Match_Success;
+ }
+ } else {
+ EmitInITBlock = false;
+ return Match_Success;
+ }
+ }
+
+ // Try to match in a new IT block. The matcher doesn't check the actual
+ // condition, so we create an IT block with a dummy condition, and fix it up
+ // once we know the actual condition.
+ startImplicitITBlock();
+ if (MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm) ==
+ Match_Success) {
+ const MCInstrDesc &MCID = MII.get(Inst.getOpcode());
+ if (MCID.isPredicable()) {
+ ITState.Cond =
+ (ARMCC::CondCodes)Inst.getOperand(MCID.findFirstPredOperandIdx())
+ .getImm();
+ EmitInITBlock = true;
+ return Match_Success;
+ }
+ }
+ discardImplicitITBlock();
+
+ // If none of these succeed, return the error we got when trying to match
+ // outside any IT blocks.
+ EmitInITBlock = false;
+ return PlainMatchResult;
+}
+
static const char *getSubtargetFeatureName(uint64_t Val);
bool ARMAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
OperandVector &Operands,
bool MatchingInlineAsm) {
MCInst Inst;
unsigned MatchResult;
+ bool PendConditionalInstruction = false;
+
+ MatchResult = MatchInstruction(Operands, Inst, ErrorInfo, MatchingInlineAsm,
+ PendConditionalInstruction, Out);
- MatchResult = MatchInstructionImpl(Operands, Inst, ErrorInfo,
- MatchingInlineAsm);
switch (MatchResult) {
case Match_Success:
// Context sensitive operand constraints aren't handled by the matcher,
return false;
Inst.setLoc(IDLoc);
- Out.EmitInstruction(Inst, getSTI());
+ if (PendConditionalInstruction) {
+ PendingConditionalInsts.push_back(Inst);
+ if (isITBlockFull() || isITBlockTerminator(Inst))
+ flushPendingInstructions(Out);
+ } else {
+ Out.EmitInstruction(Inst, getSTI());
+ }
return false;
case Match_MissingFeature: {
assert(ErrorInfo && "Unknown missing feature!");
}
void ARMAsmParser::onLabelParsed(MCSymbol *Symbol) {
+ // We need to flush the current implicit IT block on a label, because it is
+ // not legal to branch into an IT block.
+ flushPendingInstructions(getStreamer());
if (NextSymbolIsThumb) {
getParser().getStreamer().EmitThumbFunc(Symbol);
NextSymbolIsThumb = false;
--- /dev/null
+@ RUN: llvm-mc -triple thumbv7a--none-eabi -arm-implicit-it=always < %s -show-encoding | FileCheck %s
+
+@ Single instruction
+ .section test1
+@ CHECK-LABEL: test1
+ addeq r0, #1
+@ CHECK: it eq
+@ CHECK: addeq
+
+@ Multiple instructions, same condition
+ .section test2
+@ CHECK-LABEL: test2
+ addeq r0, #1
+ addeq r0, #1
+ addeq r0, #1
+ addeq r0, #1
+@ CHECK: itttt eq
+@ CHECK: addeq
+@ CHECK: addeq
+@ CHECK: addeq
+@ CHECK: addeq
+
+@ Multiple instructions, equal but opposite conditions
+ .section test3
+@ CHECK-LABEL: test3
+ addeq r0, #1
+ addne r0, #1
+ addeq r0, #1
+ addne r0, #1
+@ CHECK: itete eq
+@ CHECK: addeq
+@ CHECK: addne
+@ CHECK: addeq
+@ CHECK: addne
+
+@ Multiple instructions, unrelated conditions
+ .section test4
+@ CHECK-LABEL: test4
+ addeq r0, #1
+ addlt r0, #1
+ addeq r0, #1
+ addge r0, #1
+@ CHECK: it eq
+@ CHECK: addeq
+@ CHECK: it lt
+@ CHECK: addlt
+@ CHECK: it eq
+@ CHECK: addeq
+@ CHECK: it ge
+@ CHECK: addge
+
+@ More than 4 instructions eligible for a block
+ .section test5
+@ CHECK-LABEL: test5
+ addeq r0, #1
+ addeq r0, #1
+ addeq r0, #1
+ addeq r0, #1
+ addeq r0, #1
+ addeq r0, #1
+@ CHECK: itttt eq
+@ CHECK: addeq
+@ CHECK: addeq
+@ CHECK: addeq
+@ CHECK: addeq
+@ CHECK: itt eq
+@ CHECK: addeq
+@ CHECK: addeq
+
+@ Flush on a label
+ .section test6
+@ CHECK-LABEL: test6
+ addeq r0, #1
+label:
+ addeq r0, #1
+5:
+ addeq r0, #1
+@ CHECK: it eq
+@ CHECK: addeq
+@ CHECK: it eq
+@ CHECK: addeq
+@ CHECK: it eq
+@ CHECK: addeq
+
+@ Flush on a section-change directive
+ .section test7a
+@ CHECK-LABEL: test7a
+ addeq r0, #1
+ .section test7b
+ addeq r0, #1
+ .previous
+ addeq r0, #1
+ .pushsection test7c
+ addeq r0, #1
+ .popsection
+ addeq r0, #1
+@ CHECK: it eq
+@ CHECK: addeq
+@ CHECK: it eq
+@ CHECK: addeq
+@ CHECK: it eq
+@ CHECK: addeq
+@ CHECK: it eq
+@ CHECK: addeq
+@ CHECK: it eq
+@ CHECK: addeq
+
+@ Flush on an ISA change (even to the same ISA)
+ .section test8
+@ CHECK-LABEL: test8
+ addeq r0, #1
+ .thumb
+ addeq r0, #1
+ .arm
+ addeq r0, #1
+ .thumb
+ addeq r0, #1
+@ CHECK: it eq
+@ CHECK: addeq
+@ CHECK: it eq
+@ CHECK: addeq
+@ CHECK: addeq
+@ CHECK: it eq
+@ CHECK: addeq
+
+@ Flush on an arch, cpu or fpu change
+ .section test9
+@ CHECK-LABEL: test9
+ addeq r0, #1
+ .arch armv7-a
+ addeq r0, #1
+ .cpu cortex-a15
+ addeq r0, #1
+ .fpu vfpv3
+ addeq r0, #1
+@ CHECK: it eq
+@ CHECK: addeq
+@ CHECK: it eq
+@ CHECK: addeq
+@ CHECK: it eq
+@ CHECK: addeq
+@ CHECK: it eq
+@ CHECK: addeq
+
+@ Flush on an unpredicable instruction
+ .section test10
+@ CHECK-LABEL: test10
+ addeq r0, #1
+ setend le
+ addeq r0, #1
+ hvc #0
+ addeq r0, #1
+@ CHECK: it eq
+@ CHECK: addeq
+@ CHECK: setend le
+@ CHECK: it eq
+@ CHECK: addeq
+@ CHECK: hvc.w #0
+@ CHECK: it eq
+@ CHECK: addeq
+
+@ Flush when reaching an explicit IT instruction
+ .section test11
+@ CHECK-LABEL: test11
+ addeq r0, #1
+ it eq
+ addeq r0, #1
+@ CHECK: it eq
+@ CHECK: addeq
+@ CHECK: it eq
+@ CHECK: addeq
+
+@ Don't extend an explicit IT instruction
+ .section test12
+@ CHECK-LABEL: test12
+ it eq
+ addeq r0, #1
+ addeq r0, #1
+@ CHECK: it eq
+@ CHECK: addeq
+@ CHECK: it eq
+@ CHECK: addeq
+
+@ Branch-like instructions can only be used at the end of an IT block, so
+@ terminate it.
+ .section test13
+@ CHECK-LABEL: test13
+ .cpu cortex-a15
+ addeq pc, r0
+ addeq pc, sp, pc
+ ldreq pc, [r0, #4]
+ ldreq pc, [r0, #-4]
+ ldreq pc, [r0, r1]
+ ldreq pc, [pc, #-0]
+ moveq pc, r0
+ bleq #4
+ blxeq #4
+ blxeq r0
+ bxeq r0
+ bxjeq r0
+ tbbeq [r0, r1]
+ tbheq [r0, r1, lsl #1]
+ ereteq
+ rfeiaeq r0
+ rfeiaeq r0!
+ rfedbeq r0
+ rfedbeq r0!
+ smceq #0
+ ldmiaeq r0, {pc}
+ ldmiaeq r0!, {r1, pc}
+ ldmdbeq r0, {pc}
+ ldmdbeq r0!, {r1, pc}
+ popeq {pc}
+ .arch armv8-m.main
+ bxnseq r0
+ blxnseq r0
+@ CHECK: it eq
+@ CHECK: addeq pc, r0
+@ CHECK: it eq
+@ CHECK: addeq pc, sp, pc
+@ CHECK: it eq
+@ CHECK: ldreq.w pc, [r0, #4]
+@ CHECK: it eq
+@ CHECK: ldreq pc, [r0, #-4]
+@ CHECK: it eq
+@ CHECK: ldreq.w pc, [r0, r1]
+@ CHECK: it eq
+@ CHECK: ldreq.w pc, [pc, #-0]
+@ CHECK: it eq
+@ CHECK: moveq pc, r0
+@ CHECK: it eq
+@ CHECK: bleq #4
+@ CHECK: it eq
+@ CHECK: blxeq #4
+@ CHECK: it eq
+@ CHECK: blxeq r0
+@ CHECK: it eq
+@ CHECK: bxeq r0
+@ CHECK: it eq
+@ CHECK: bxjeq r0
+@ CHECK: it eq
+@ CHECK: tbbeq [r0, r1]
+@ CHECK: it eq
+@ CHECK: tbheq [r0, r1, lsl #1]
+@ CHECK: it eq
+@ CHECK: ereteq
+@ CHECK: it eq
+@ CHECK: rfeiaeq r0
+@ CHECK: it eq
+@ CHECK: rfeiaeq r0!
+@ CHECK: it eq
+@ CHECK: rfedbeq r0
+@ CHECK: it eq
+@ CHECK: rfedbeq r0!
+@ CHECK: it eq
+@ CHECK: smceq #0
+@ CHECK: it eq
+@ CHECK: ldmeq.w r0, {pc}
+@ CHECK: it eq
+@ CHECK: ldmeq.w r0!, {r1, pc}
+@ CHECK: it eq
+@ CHECK: ldmdbeq r0, {pc}
+@ CHECK: it eq
+@ CHECK: ldmdbeq r0!, {r1, pc}
+@ CHECK: it eq
+@ CHECK: popeq {pc}
+@ CHECK: it eq
+@ CHECK: bxnseq r0
+@ CHECK: it eq
+@ CHECK: blxnseq r0
+
+@ Thumb 16-bit ALU instructions set the flags iff they are not in an IT block,
+@ so instruction matching must change when generating an implicit IT block.
+ .section test14
+@ CHECK-LABEL: test14
+@ Outside an IT block, the 16-bit encoding must set flags
+ add r0, #1
+@ CHECK:add.w r0, r0, #1 @ encoding: [0x00,0xf1,0x01,0x00]
+ adds r0, #1
+@ CHECK: adds r0, #1 @ encoding: [0x01,0x30]
+@ Inside an IT block, the 16-bit encoding can not set flags
+ addeq r0, #1
+@ CHECK: itt eq
+@ CHECK: addeq r0, #1 @ encoding: [0x01,0x30]
+ addseq r0, #1
+@ CHECK: addseq.w r0, r0, #1 @ encoding: [0x10,0xf1,0x01,0x00]
+
+@ Some variants of the B instruction have their own condition code field, and
+@ are not valid in IT blocks.
+ .section test15
+@ CHECK-LABEL: test15
+@ Outside of an IT block, the 4 variants (narrow/wide,
+@ predicated/non-predicated) are selected as normal, and the predicated
+@ encodings are used instead of opening a new IT block:
+ b #0x100
+@ CHECK: b #256 @ encoding: [0x80,0xe0]
+ b #0x800
+@ CHECK: b.w #2048 @ encoding: [0x00,0xf0,0x00,0xbc]
+ beq #0x4
+@ CHECK-NOT: it
+@ CHECK: beq #4 @ encoding: [0x02,0xd0]
+ beq #0x100
+@ CHECK-NOT: it
+@ CHECK: beq.w #256 @ encoding: [0x00,0xf0,0x80,0x80]
+
+@ We could support "beq #0x100000" to "beq #0x1fffffc" by using t2Bcc in
+@ an IT block (these currently fail as the target is out of range). However, long
+@ ranges like this are rarely assembly-time constants, so this probably isn't
+@ worth doing.
+
+@ If we already have an open IT block, we can use the non-predicated encodings,
+@ which have a greater range:
+ addeq r0, r1
+ beq #0x4
+@ CHECK: itt eq
+@ CHECK: addeq r0, r1
+@ CHECK: beq #4 @ encoding: [0x02,0xe0]
+ addeq r0, r1
+ beq #0x100
+@ CHECK: itt eq
+@ CHECK: addeq r0, r1
+@ CHECK: beq #256 @ encoding: [0x80,0xe0]
+ addeq r0, r1
+ beq #0x800
+@ CHECK: itt eq
+@ CHECK: addeq r0, r1
+@ CHECK: beq.w #2048 @ encoding: [0x00,0xf0,0x00,0xbc]
+
+@ If we have an open but incompatible IT block, we close it and use the
+@ self-predicated encodings, without an IT block:
+ addeq r0, r1
+ bgt #0x4
+@ CHECK: it eq
+@ CHECK: addeq r0, r1
+@ CHECK: bgt #4 @ encoding: [0x02,0xdc]
+ addeq r0, r1
+ bgt #0x100
+@ CHECK: it eq
+@ CHECK: addeq r0, r1
+@ CHECK: bgt.w #256 @ encoding: [0x00,0xf3,0x80,0x80]
+
+@ Breakpoint instructions are allowed in IT blocks, but are always executed
+@ regardless of the condition flags. We could continue an IT block through
+@ them, but currently do not.
+ .section test16
+@ CHECK-LABEL: test16
+ addeq r0, r1
+ bkpt #0
+ addeq r0, r1
+@ CHECK: it eq
+@ CHECK: addeq r0, r1
+@ CHECK: bkpt #0
+@ CHECK: it eq
+@ CHECK: addeq r0, r1
+
+@ The .if directive causes entire assembly statments to be dropped before they
+@ reach the IT block generation code. This happens to be exactly what we want,
+@ and allows IT blocks to extend into and out of .if blocks. Only one arm of the
+@ .if will be seen by the IT state tracking code, so the subeq shouldn't have
+@ any effect here.
+ .section test17
+@ CHECK-LABEL: test17
+ addeq r0, r1
+ .if 1
+ addeq r0, r1
+ .else
+ subeq r0, r1
+ .endif
+ addeq r0, r1
+@ CHECK: ittt eq
+@ CHECK: addeq
+@ CHECK: addeq
+@ CHECK: addeq
+
+@ TODO: There are some other directives which we could continue through, such
+@ as .set and .global, but we currently conservatively flush the IT block before
+@ every directive (except for .if and friends, which are handled separately).
+ .section test18
+@ CHECK-LABEL: test18
+ addeq r0, r1
+ .set s, 1
+ addeq r0, r1
+@ CHECK: it eq
+@ CHECK: addeq
+@ CHECK: it eq
+@ CHECK: addeq
+
+@ The .rept directive can be used to create long IT blocks.
+ .section test19
+@ CHECK-LABEL: test19
+ .rept 3
+ addeq r0, r1
+ subne r0, r1
+ .endr
+@ CHECK: itete eq
+@ CHECK: addeq r0, r1
+@ CHECK: subne.w r0, r0, r1
+@ CHECK: addeq r0, r1
+@ CHECK: subne.w r0, r0, r1
+@ CHECK: ite eq
+@ CHECK: addeq r0, r1
+@ CHECK: subne.w r0, r0, r1
+
+@ Flush at end of file
+ .section test99
+@ CHECK-LABEL: test99
+ addeq r0, #1
+@ CHECK: it eq
+@ CHECK: addeq