[ARM][MC] Move information about variadic register defs into tablegen
Currently, variadic operands on an MCInst are assumed to be uses, because they come after the defs. However, this is not always the case, for example the Arm/Thumb LDM instructions write to a variable number of registers. This adds a property of instruction definitions which can be used to mark variadic operands as defs. This only affects MCInst, because MachineInstruction already tracks use/def per operand in each instance of the instruction, so can already represent this. This property can then be checked in MCInstrDesc, allowing us to remove some special cases in ARMAsmParser::isITBlockTerminator. Differential revision: https://reviews.llvm.org/D54853 llvm-svn: 348114
This commit is contained in:
@@ -151,7 +151,8 @@ enum Flag {
|
||||
InsertSubreg,
|
||||
Convergent,
|
||||
Add,
|
||||
Trap
|
||||
Trap,
|
||||
VariadicOpsAreDefs,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -383,6 +384,11 @@ public:
|
||||
/// additional values.
|
||||
bool isConvergent() const { return Flags & (1ULL << MCID::Convergent); }
|
||||
|
||||
/// Return true if variadic operands of this instruction are definitions.
|
||||
bool variadicOpsAreDefs() const {
|
||||
return Flags & (1ULL << MCID::VariadicOpsAreDefs);
|
||||
}
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Side Effect Analysis
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
@@ -479,6 +479,7 @@ class Instruction {
|
||||
bit isInsertSubreg = 0; // Is this instruction a kind of insert subreg?
|
||||
// If so, make sure to override
|
||||
// TargetInstrInfo::getInsertSubregLikeInputs.
|
||||
bit variadicOpsAreDefs = 0; // Are variadic operands definitions?
|
||||
|
||||
// Does the instruction have side effects that are not captured by any
|
||||
// operands of the instruction or other flags?
|
||||
|
||||
@@ -39,15 +39,6 @@ bool MCInstrDesc::mayAffectControlFlow(const MCInst &MI,
|
||||
return false;
|
||||
if (hasDefOfPhysReg(MI, PC, RI))
|
||||
return true;
|
||||
// A variadic instruction may define PC in the variable operand list.
|
||||
// There's currently no indication of which entries in a variable
|
||||
// list are defs and which are uses. While that's the case, this function
|
||||
// needs to assume they're defs in order to be conservatively correct.
|
||||
for (int i = NumOperands, e = MI.getNumOperands(); i != e; ++i) {
|
||||
if (MI.getOperand(i).isReg() &&
|
||||
RI.isSubRegisterEq(PC, MI.getOperand(i).getReg()))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -66,5 +57,10 @@ bool MCInstrDesc::hasDefOfPhysReg(const MCInst &MI, unsigned Reg,
|
||||
if (MI.getOperand(i).isReg() &&
|
||||
RI.isSubRegisterEq(Reg, MI.getOperand(i).getReg()))
|
||||
return true;
|
||||
if (variadicOpsAreDefs())
|
||||
for (int i = NumOperands - 1, e = MI.getNumOperands(); i != e; ++i)
|
||||
if (MI.getOperand(i).isReg() &&
|
||||
RI.isSubRegisterEq(Reg, MI.getOperand(i).getReg()))
|
||||
return true;
|
||||
return hasImplicitDefOfPhysReg(Reg, &RI);
|
||||
}
|
||||
|
||||
@@ -3334,7 +3334,7 @@ multiclass arm_ldst_mult<string asm, string sfx, bit L_bit, bit P_bit, Format f,
|
||||
|
||||
let hasSideEffects = 0 in {
|
||||
|
||||
let mayLoad = 1, hasExtraDefRegAllocReq = 1 in
|
||||
let mayLoad = 1, hasExtraDefRegAllocReq = 1, variadicOpsAreDefs = 1 in
|
||||
defm LDM : arm_ldst_mult<"ldm", "", 1, 0, LdStMulFrm, IIC_iLoad_m,
|
||||
IIC_iLoad_mu>, ComplexDeprecationPredicate<"ARMLoad">;
|
||||
|
||||
|
||||
@@ -781,7 +781,7 @@ defm tSTRH : thumb_st_rr_ri_enc<0b001, 0b1000, t_addrmode_rr,
|
||||
// These require base address to be written back or one of the loaded regs.
|
||||
let hasSideEffects = 0 in {
|
||||
|
||||
let mayLoad = 1, hasExtraDefRegAllocReq = 1 in
|
||||
let mayLoad = 1, hasExtraDefRegAllocReq = 1, variadicOpsAreDefs = 1 in
|
||||
def tLDMIA : T1I<(outs), (ins tGPR:$Rn, pred:$p, reglist:$regs, variable_ops),
|
||||
IIC_iLoad_m, "ldm${p}\t$Rn, $regs", []>, T1Encoding<{1,1,0,0,1,?}> {
|
||||
bits<3> Rn;
|
||||
@@ -826,7 +826,8 @@ def : InstAlias<"ldm${p} $Rn!, $regs",
|
||||
(tLDMIA tGPR:$Rn, pred:$p, reglist:$regs), 0>,
|
||||
Requires<[IsThumb, IsThumb1Only]>;
|
||||
|
||||
let mayLoad = 1, Uses = [SP], Defs = [SP], hasExtraDefRegAllocReq = 1 in
|
||||
let mayLoad = 1, Uses = [SP], Defs = [SP], hasExtraDefRegAllocReq = 1,
|
||||
variadicOpsAreDefs = 1 in
|
||||
def tPOP : T1I<(outs), (ins pred:$p, reglist:$regs, variable_ops),
|
||||
IIC_iPop,
|
||||
"pop${p}\t$regs", []>,
|
||||
|
||||
@@ -1775,7 +1775,7 @@ multiclass thumb2_ld_mult<string asm, InstrItinClass itin,
|
||||
|
||||
let hasSideEffects = 0 in {
|
||||
|
||||
let mayLoad = 1, hasExtraDefRegAllocReq = 1 in
|
||||
let mayLoad = 1, hasExtraDefRegAllocReq = 1, variadicOpsAreDefs = 1 in
|
||||
defm t2LDM : thumb2_ld_mult<"ldm", IIC_iLoad_m, IIC_iLoad_mu, 1>;
|
||||
|
||||
multiclass thumb2_st_mult<string asm, InstrItinClass itin,
|
||||
|
||||
@@ -9177,33 +9177,9 @@ bool ARMAsmParser::isITBlockTerminator(MCInst &Inst) const {
|
||||
|
||||
// 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))
|
||||
if (MCID.hasDefOfPhysReg(Inst, 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::tLDMIA:
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -370,6 +370,7 @@ CodeGenInstruction::CodeGenInstruction(Record *R)
|
||||
isConvergent = R->getValueAsBit("isConvergent");
|
||||
hasNoSchedulingInfo = R->getValueAsBit("hasNoSchedulingInfo");
|
||||
FastISelShouldIgnore = R->getValueAsBit("FastISelShouldIgnore");
|
||||
variadicOpsAreDefs = R->getValueAsBit("variadicOpsAreDefs");
|
||||
|
||||
bool Unset;
|
||||
mayLoad = R->getValueAsBitOrUnset("mayLoad", Unset);
|
||||
|
||||
@@ -275,6 +275,7 @@ template <typename T> class ArrayRef;
|
||||
bool FastISelShouldIgnore : 1;
|
||||
bool hasChain : 1;
|
||||
bool hasChain_Inferred : 1;
|
||||
bool variadicOpsAreDefs : 1;
|
||||
|
||||
std::string DeprecatedReason;
|
||||
bool HasComplexDeprecationPredicate;
|
||||
|
||||
@@ -138,6 +138,7 @@ void EmitInstrDocs(RecordKeeper &RK, raw_ostream &OS) {
|
||||
FLAG(isInsertSubreg)
|
||||
FLAG(isConvergent)
|
||||
FLAG(hasNoSchedulingInfo)
|
||||
FLAG(variadicOpsAreDefs)
|
||||
if (!FlagStrings.empty()) {
|
||||
OS << "Flags: ";
|
||||
bool IsFirst = true;
|
||||
|
||||
@@ -625,6 +625,7 @@ void InstrInfoEmitter::emitRecord(const CodeGenInstruction &Inst, unsigned Num,
|
||||
if (Inst.isExtractSubreg) OS << "|(1ULL<<MCID::ExtractSubreg)";
|
||||
if (Inst.isInsertSubreg) OS << "|(1ULL<<MCID::InsertSubreg)";
|
||||
if (Inst.isConvergent) OS << "|(1ULL<<MCID::Convergent)";
|
||||
if (Inst.variadicOpsAreDefs) OS << "|(1ULL<<MCID::VariadicOpsAreDefs)";
|
||||
|
||||
// Emit all of the target-specific flags...
|
||||
BitsInit *TSF = Inst.TheDef->getValueAsBitsInit("TSFlags");
|
||||
|
||||
Reference in New Issue
Block a user