[ARM] Refactor handling of IT mask operands.

During assembly, the mask operand to an IT instruction (storing the
sequence of T/E for 'Then' and 'Else') is parsed out of the mnemonic
into a representation that encodes 'Then' and 'Else' in the same way
regardless of the condition code. At some point during encoding it has
to be converted into the instruction encoding used in the
architecture, in which the mask encodes a sequence of replacement
low-order bits for the condition code, so that which bit value means
'then' and which 'else' depends on whether the original condition code
had its low bit set.

Previously, that transformation was done by processInstruction(), half
way through assembly. So an MCOperand storing an IT mask would
sometimes store it in one format, and sometimes in the other,
depending on where in the assembly pipeline you were. You can see this
in diagnostics from `llvm-mc -debug -triple=thumbv8a -show-inst`, for
example: if you give it an instruction such as `itete eq`, you'd see
an `<MCOperand Imm:5>` in a diagnostic become `<MCOperand Imm:11>` in
the final output.

Having the same data structure store values with time-dependent
semantics is confusing already, and it will get more confusing when we
introduce the MVE VPT instruction which reuses the Then/Else bitmask
idea in a different context. So I'm refactoring: now, all `ARMOperand`
and `MCOperand` representations of an IT mask work exactly the same
way, namely, 0 means 'Then' and 1 means 'Else', regardless of what
original predicate is being referred to. The architectural encoding of
IT that depends on the original condition is now constructed at the
point when we turn the `MCOperand` into the final instruction bit
pattern, and decoded similarly in the disassembler.

The previous condition-independent parse-time format used 0 for Else
and 1 for Then. I've taken the opportunity to flip the sense of it
while I'm changing all of this anyway, because it seems to me more
natural to use 0 for 'leave the starting condition unchanged' and 1
for 'invert it', as if those bits were an XOR mask.

Reviewers: ostannard

Subscribers: javed.absar, kristof.beyls, hiraditya, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D63219

llvm-svn: 363244
This commit is contained in:
Simon Tatham 2019-06-13 10:01:52 +00:00
parent 86b7f865ac
commit 848d3d0d2c
6 changed files with 88 additions and 64 deletions

View File

@ -25,6 +25,7 @@ def it_mask_asmoperand : AsmOperandClass { let Name = "ITMask"; }
def it_mask : Operand<i32> {
let PrintMethod = "printThumbITMask";
let ParserMatchClass = it_mask_asmoperand;
let EncoderMethod = "getITMaskOpValue";
}
// t2_shift_imm: An integer that encodes a shift amount and the type of shift

View File

@ -90,6 +90,16 @@ static cl::opt<bool> AddBuildAttributes("arm-add-build-attributes",
enum VectorLaneTy { NoLanes, AllLanes, IndexedLane };
static inline unsigned extractITMaskBit(unsigned Mask, unsigned Position) {
// Position==0 means we're not in an IT block at all. Position==1
// means we want the first state bit, which is always 0 (Then).
// Position==2 means we want the second state bit, stored at bit 3
// of Mask, and so on downwards. So (5 - Position) will shift the
// right bit down to bit 0, including the always-0 bit at bit 4 for
// the mandatory initial Then.
return (Mask >> (5 - Position) & 1);
}
class UnwindContext {
using Locs = SmallVector<SMLoc, 4>;
@ -226,11 +236,10 @@ class ARMAsmParser : public MCTargetAsmParser {
}
// Emit the IT instruction
unsigned Mask = getITMaskEncoding();
MCInst ITInst;
ITInst.setOpcode(ARM::t2IT);
ITInst.addOperand(MCOperand::createImm(ITState.Cond));
ITInst.addOperand(MCOperand::createImm(Mask));
ITInst.addOperand(MCOperand::createImm(ITState.Mask));
Out.EmitInstruction(ITInst, getSTI());
// Emit the conditonal instructions
@ -288,27 +297,10 @@ class ARMAsmParser : public MCTargetAsmParser {
return MRI->getSubReg(QReg, ARM::dsub_0);
}
// 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);
unsigned MaskBit = extractITMaskBit(ITState.Mask, ITState.CurPosition);
return MaskBit ? ARMCC::getOppositeCondition(ITState.Cond) : ITState.Cond;
}
// Invert the condition of the current IT block slot without changing any
@ -338,7 +330,7 @@ class ARMAsmParser : public MCTargetAsmParser {
// Keep any existing condition bits.
NewMask |= ITState.Mask & (0xE << TZ);
// Insert the new condition bit.
NewMask |= (Cond == ITState.Cond) << TZ;
NewMask |= (Cond != ITState.Cond) << TZ;
// Move the trailing 1 down one bit.
NewMask |= 1 << (TZ - 1);
ITState.Mask = NewMask;
@ -353,9 +345,10 @@ class ARMAsmParser : public MCTargetAsmParser {
ITState.IsExplicit = false;
}
// 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.
// Create a new explicit IT block with the given condition and mask.
// The mask should be in the format used in ARMOperand and
// MCOperand, with a 1 implying 'e', regardless of the low bit of
// the condition.
void startExplicitITBlock(ARMCC::CondCodes Cond, unsigned Mask) {
assert(!inITBlock());
ITState.Cond = Cond;
@ -3355,10 +3348,10 @@ void ARMOperand::print(raw_ostream &OS) const {
break;
case k_ITCondMask: {
static const char *const MaskStr[] = {
"(invalid)", "(teee)", "(tee)", "(teet)",
"(te)", "(tete)", "(tet)", "(tett)",
"(t)", "(ttee)", "(tte)", "(ttet)",
"(tt)", "(ttte)", "(ttt)", "(tttt)"
"(invalid)", "(tttt)", "(ttt)", "(ttte)",
"(tt)", "(ttet)", "(tte)", "(ttee)",
"(t)", "(tett)", "(tet)", "(tete)",
"(te)", "(teet)", "(tee)", "(teee)",
};
assert((ITMask.Mask & 0xf) == ITMask.Mask);
OS << "<it-mask " << MaskStr[ITMask.Mask] << ">";
@ -6272,11 +6265,14 @@ bool ARMAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
Operands.push_back(ARMOperand::CreateToken(Mnemonic, NameLoc));
// Handle the IT instruction ITMask. Convert it to a bitmask. This
// is the mask as it will be for the IT encoding if the conditional
// encoding has a '1' as it's bit0 (i.e. 't' ==> '1'). In the case
// where the conditional bit0 is zero, the instruction post-processing
// will adjust the mask accordingly.
// Handle the mask for IT instructions. In ARMOperand and MCOperand,
// this is stored in a format independent of the condition code: the
// lowest set bit indicates the end of the encoding, and above that,
// a 1 bit indicates 'else', and an 0 indicates 'then'. E.g.
// IT -> 1000
// ITx -> x100 (ITT -> 0100, ITE -> 1100)
// ITxy -> xy10 (e.g. ITET -> 1010)
// ITxyz -> xyz1 (e.g. ITEET -> 1101)
if (Mnemonic == "it") {
SMLoc Loc = SMLoc::getFromPointer(NameLoc.getPointer() + 2);
if (ITMask.size() > 3) {
@ -6289,7 +6285,7 @@ bool ARMAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
return Error(Loc, "illegal IT block condition mask '" + ITMask + "'");
}
Mask >>= 1;
if (ITMask[i - 1] == 't')
if (ITMask[i - 1] == 'e')
Mask |= 8;
}
Operands.push_back(ARMOperand::CreateITMask(Mask, Loc));
@ -6681,11 +6677,10 @@ bool ARMAsmParser::validateInstruction(MCInst &Inst,
unsigned Cond = Inst.getOperand(0).getImm();
unsigned Mask = Inst.getOperand(1).getImm();
// Mask hasn't been modified to the IT instruction encoding yet so
// conditions only allowing a 't' are a block of 1s starting at bit 3
// followed by all 0s. Easiest way is to just list the 4 possibilities.
if (Cond == ARMCC::AL && Mask != 8 && Mask != 12 && Mask != 14 &&
Mask != 15)
// Conditions only allowing a 't' are those with no set bit except
// the lowest-order one that indicates the end of the sequence. In
// other words, powers of 2.
if (Cond == ARMCC::AL && countPopulation(Mask) != 1)
return Error(Loc, "unpredictable IT predicate sequence");
break;
}
@ -9260,15 +9255,11 @@ bool ARMAsmParser::processInstruction(MCInst &Inst,
}
case ARM::ITasm:
case ARM::t2IT: {
MCOperand &MO = Inst.getOperand(1);
unsigned Mask = MO.getImm();
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?!");
startExplicitITBlock(Cond, Mask);
MO.setImm(getITMaskEncoding());
startExplicitITBlock(ARMCC::CondCodes(Inst.getOperand(0).getImm()),
Inst.getOperand(1).getImm());
break;
}
case ARM::t2LSLrr:

View File

@ -63,22 +63,19 @@ namespace {
return ITStates.size() == 1;
}
// Called when decoding an IT instruction. Sets the IT state for the following
// instructions that for the IT block. Firstcond and Mask correspond to the
// fields in the IT instruction encoding.
// Called when decoding an IT instruction. Sets the IT state for
// the following instructions that for the IT block. Firstcond
// corresponds to the field in the IT instruction encoding; Mask
// is in the MCOperand format in which 1 means 'else' and 0 'then'.
void setITState(char Firstcond, char Mask) {
// (3 - the number of trailing zeros) is the number of then / else.
unsigned CondBit0 = Firstcond & 1;
unsigned NumTZ = countTrailingZeros<uint8_t>(Mask);
unsigned char CCBits = static_cast<unsigned char>(Firstcond & 0xf);
assert(NumTZ <= 3 && "Invalid IT mask!");
// push condition codes onto the stack the correct order for the pops
for (unsigned Pos = NumTZ+1; Pos <= 3; ++Pos) {
bool T = ((Mask >> Pos) & 1) == CondBit0;
if (T)
ITStates.push_back(CCBits);
else
ITStates.push_back(CCBits ^ 1);
unsigned Else = (Mask >> Pos) & 1;
ITStates.push_back(CCBits ^ Else);
}
ITStates.push_back(CCBits);
}
@ -5176,6 +5173,16 @@ static DecodeStatus DecodeIT(MCInst &Inst, unsigned Insn,
if (mask == 0x0)
return MCDisassembler::Fail;
// IT masks are encoded as a sequence of replacement low-order bits
// for the condition code. So if the low bit of the starting
// condition code is 1, then we have to flip all the bits above the
// terminating bit (which is the lowest 1 bit).
if (pred & 1) {
unsigned LowBit = mask & -mask;
unsigned BitsAboveLowBit = 0xF & (-LowBit << 1);
mask ^= BitsAboveLowBit;
}
Inst.addOperand(MCOperand::createImm(pred));
Inst.addOperand(MCOperand::createImm(mask));
return S;

View File

@ -1039,16 +1039,13 @@ void ARMInstPrinter::printThumbITMask(const MCInst *MI, unsigned OpNum,
raw_ostream &O) {
// (3 - the number of trailing zeros) is the number of then / else.
unsigned Mask = MI->getOperand(OpNum).getImm();
unsigned Firstcond = MI->getOperand(OpNum - 1).getImm();
unsigned CondBit0 = Firstcond & 1;
unsigned NumTZ = countTrailingZeros(Mask);
assert(NumTZ <= 3 && "Invalid IT mask!");
for (unsigned Pos = 3, e = NumTZ; Pos > e; --Pos) {
bool T = ((Mask >> Pos) & 1) == CondBit0;
if (T)
O << 't';
else
if ((Mask >> Pos) & 1)
O << 'e';
else
O << 't';
}
}

View File

@ -162,6 +162,9 @@ public:
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;
uint32_t getITMaskOpValue(const MCInst &MI, unsigned OpIdx,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;
/// getAddrModeImm12OpValue - Return encoding info for 'reg +/- imm12'
/// operand.
@ -829,6 +832,33 @@ getT2AdrLabelOpValue(const MCInst &MI, unsigned OpIdx,
return Val;
}
/// getITMaskOpValue - Return the architectural encoding of an IT
/// predication mask, given the MCOperand format.
uint32_t ARMMCCodeEmitter::
getITMaskOpValue(const MCInst &MI, unsigned OpIdx,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
const MCOperand MaskMO = MI.getOperand(OpIdx);
assert(MaskMO.isImm() && "Unexpected operand type!");
unsigned Mask = MaskMO.getImm();
// IT masks are encoded as a sequence of replacement low-order bits
// for the condition code. So if the low bit of the starting
// condition code is 1, then we have to flip all the bits above the
// terminating bit (which is the lowest 1 bit).
assert(OpIdx > 0 && "IT mask appears first!");
const MCOperand CondMO = MI.getOperand(OpIdx-1);
assert(CondMO.isImm() && "Unexpected operand type!");
if (CondMO.getImm() & 1) {
unsigned LowBit = Mask & -Mask;
unsigned BitsAboveLowBit = 0xF & (-LowBit << 1);
Mask ^= BitsAboveLowBit;
}
return Mask;
}
/// getThumbAdrLabelOpValue - Return encoding info for 8-bit immediate ADR label
/// target.
uint32_t ARMMCCodeEmitter::

View File

@ -245,7 +245,7 @@ bool Thumb2ITBlockPass::InsertITInstructions(MachineBasicBlock &MBB) {
unsigned NPredReg = 0;
ARMCC::CondCodes NCC = getITInstrPredicate(*NMI, NPredReg);
if (NCC == CC || NCC == OCC) {
Mask |= (NCC & 1) << Pos;
Mask |= ((NCC ^ CC) & 1) << Pos;
// Add implicit use of ITSTATE.
NMI->addOperand(MachineOperand::CreateReg(ARM::ITSTATE, false/*ifDef*/,
true/*isImp*/, false/*isKill*/));
@ -269,8 +269,6 @@ bool Thumb2ITBlockPass::InsertITInstructions(MachineBasicBlock &MBB) {
// Finalize IT mask.
Mask |= (1 << Pos);
// Tag along (firstcond[0] << 4) with the mask.
Mask |= (CC & 1) << 4;
MIB.addImm(Mask);
// Last instruction in IT block kills ITSTATE.