forked from OSchip/llvm-project
Lower ARM adds/subs to add/sub after adding optional CPSR operand.
This is still a hack until we can teach tblgen to generate the optional CPSR operand rather than an implicit CPSR def. But the strangeness is now limited to the selection DAG. ADD/SUB MI's no longer have implicit CPSR defs, nor do we allow flag setting variants of these opcodes in machine code. There are several corner cases to consider, and getting one wrong would previously lead to nasty miscompilation. It's not the first time I've debugged one, so this time I added enough verification to ensure it won't happen again. llvm-svn: 140228
This commit is contained in:
parent
3f1fdf1b31
commit
924123acb3
|
@ -49,7 +49,7 @@ public:
|
||||||
: CallFrameSetupOpcode(CFSetupOpcode),
|
: CallFrameSetupOpcode(CFSetupOpcode),
|
||||||
CallFrameDestroyOpcode(CFDestroyOpcode) {
|
CallFrameDestroyOpcode(CFDestroyOpcode) {
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~TargetInstrInfo();
|
virtual ~TargetInstrInfo();
|
||||||
|
|
||||||
/// getRegClass - Givem a machine instruction descriptor, returns the register
|
/// getRegClass - Givem a machine instruction descriptor, returns the register
|
||||||
|
@ -671,6 +671,12 @@ public:
|
||||||
bool hasLowDefLatency(const InstrItineraryData *ItinData,
|
bool hasLowDefLatency(const InstrItineraryData *ItinData,
|
||||||
const MachineInstr *DefMI, unsigned DefIdx) const;
|
const MachineInstr *DefMI, unsigned DefIdx) const;
|
||||||
|
|
||||||
|
/// verifyInstruction - Perform target specific instruction verification.
|
||||||
|
virtual
|
||||||
|
bool verifyInstruction(const MachineInstr *MI, StringRef &ErrInfo) const {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int CallFrameSetupOpcode, CallFrameDestroyOpcode;
|
int CallFrameSetupOpcode, CallFrameDestroyOpcode;
|
||||||
};
|
};
|
||||||
|
|
|
@ -570,6 +570,9 @@ void MachineVerifier::visitMachineInstrBefore(const MachineInstr *MI) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StringRef ErrorInfo;
|
||||||
|
if (!TII->verifyInstruction(MI, ErrorInfo))
|
||||||
|
report(ErrorInfo.data(), MI);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -763,7 +763,9 @@ EmitMachineNode(SDNode *Node, bool IsClone, bool IsCloned,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run post-isel target hook to adjust this instruction if needed.
|
// Run post-isel target hook to adjust this instruction if needed.
|
||||||
|
#ifdef NDEBUG
|
||||||
if (II.hasPostISelHook())
|
if (II.hasPostISelHook())
|
||||||
|
#endif
|
||||||
TLI->AdjustInstrPostInstrSelection(MI, Node);
|
TLI->AdjustInstrPostInstrSelection(MI, Node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -179,12 +179,9 @@ TargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI,
|
||||||
|
|
||||||
void TargetLowering::AdjustInstrPostInstrSelection(MachineInstr *MI,
|
void TargetLowering::AdjustInstrPostInstrSelection(MachineInstr *MI,
|
||||||
SDNode *Node) const {
|
SDNode *Node) const {
|
||||||
#ifndef NDEBUG
|
assert(!MI->getDesc().hasPostISelHook() &&
|
||||||
dbgs() << "If a target marks an instruction with "
|
"If a target marks an instruction with 'hasPostISelHook', "
|
||||||
"'hasPostISelHook', it must implement "
|
"it must implement TargetLowering::AdjustInstrPostInstrSelection!");
|
||||||
"TargetLowering::AdjustInstrPostInstrSelection!";
|
|
||||||
#endif
|
|
||||||
llvm_unreachable(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
|
@ -1167,6 +1167,9 @@ void ARMAsmPrinter::EmitInstruction(const MachineInstr *MI) {
|
||||||
if (emitPseudoExpansionLowering(OutStreamer, MI))
|
if (emitPseudoExpansionLowering(OutStreamer, MI))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
assert(!convertAddSubFlagsOpcode(MI->getOpcode()) &&
|
||||||
|
"Pseudo flag setting opcode should be expanded early");
|
||||||
|
|
||||||
// Check for manual lowerings.
|
// Check for manual lowerings.
|
||||||
unsigned Opc = MI->getOpcode();
|
unsigned Opc = MI->getOpcode();
|
||||||
switch (Opc) {
|
switch (Opc) {
|
||||||
|
|
|
@ -1410,6 +1410,57 @@ int llvm::getMatchingCondBranchOpcode(int Opc) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Map pseudo instructions that imply an 'S' bit onto real opcodes. Whether the
|
||||||
|
/// instruction is encoded with an 'S' bit is determined by the optional CPSR
|
||||||
|
/// def operand.
|
||||||
|
///
|
||||||
|
/// This will go away once we can teach tblgen how to set the optional CPSR def
|
||||||
|
/// operand itself.
|
||||||
|
struct AddSubFlagsOpcodePair {
|
||||||
|
unsigned PseudoOpc;
|
||||||
|
unsigned MachineOpc;
|
||||||
|
};
|
||||||
|
|
||||||
|
static AddSubFlagsOpcodePair AddSubFlagsOpcodeMap[] = {
|
||||||
|
{ARM::ADDSri, ARM::ADDri},
|
||||||
|
{ARM::ADDSrr, ARM::ADDrr},
|
||||||
|
{ARM::ADDSrsi, ARM::ADDrsi},
|
||||||
|
{ARM::ADDSrsr, ARM::ADDrsr},
|
||||||
|
|
||||||
|
{ARM::SUBSri, ARM::SUBri},
|
||||||
|
{ARM::SUBSrr, ARM::SUBrr},
|
||||||
|
{ARM::SUBSrsi, ARM::SUBrsi},
|
||||||
|
{ARM::SUBSrsr, ARM::SUBrsr},
|
||||||
|
|
||||||
|
{ARM::RSBSri, ARM::RSBri},
|
||||||
|
{ARM::RSBSrr, ARM::RSBrr},
|
||||||
|
{ARM::RSBSrsi, ARM::RSBrsi},
|
||||||
|
{ARM::RSBSrsr, ARM::RSBrsr},
|
||||||
|
|
||||||
|
{ARM::t2ADDSri, ARM::t2ADDri},
|
||||||
|
{ARM::t2ADDSrr, ARM::t2ADDrr},
|
||||||
|
{ARM::t2ADDSrs, ARM::t2ADDrs},
|
||||||
|
|
||||||
|
{ARM::t2SUBSri, ARM::t2SUBri},
|
||||||
|
{ARM::t2SUBSrr, ARM::t2SUBrr},
|
||||||
|
{ARM::t2SUBSrs, ARM::t2SUBrs},
|
||||||
|
|
||||||
|
{ARM::t2RSBSri, ARM::t2RSBri},
|
||||||
|
{ARM::t2RSBSrs, ARM::t2RSBrs},
|
||||||
|
};
|
||||||
|
|
||||||
|
unsigned llvm::convertAddSubFlagsOpcode(unsigned OldOpc) {
|
||||||
|
static const int NPairs =
|
||||||
|
sizeof(AddSubFlagsOpcodeMap) / sizeof(AddSubFlagsOpcodePair);
|
||||||
|
for (AddSubFlagsOpcodePair *OpcPair = &AddSubFlagsOpcodeMap[0],
|
||||||
|
*End = &AddSubFlagsOpcodeMap[NPairs]; OpcPair != End; ++OpcPair) {
|
||||||
|
if (OldOpc == OpcPair->PseudoOpc) {
|
||||||
|
return OpcPair->MachineOpc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void llvm::emitARMRegPlusImmediate(MachineBasicBlock &MBB,
|
void llvm::emitARMRegPlusImmediate(MachineBasicBlock &MBB,
|
||||||
MachineBasicBlock::iterator &MBBI, DebugLoc dl,
|
MachineBasicBlock::iterator &MBBI, DebugLoc dl,
|
||||||
unsigned DestReg, unsigned BaseReg, int NumBytes,
|
unsigned DestReg, unsigned BaseReg, int NumBytes,
|
||||||
|
@ -2645,6 +2696,15 @@ hasLowDefLatency(const InstrItineraryData *ItinData,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ARMBaseInstrInfo::verifyInstruction(const MachineInstr *MI,
|
||||||
|
StringRef &ErrInfo) const {
|
||||||
|
if (convertAddSubFlagsOpcode(MI->getOpcode())) {
|
||||||
|
ErrInfo = "Pseudo flag setting opcodes only exist in Selection DAG";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ARMBaseInstrInfo::isFpMLxInstruction(unsigned Opcode, unsigned &MulOpc,
|
ARMBaseInstrInfo::isFpMLxInstruction(unsigned Opcode, unsigned &MulOpc,
|
||||||
unsigned &AddSubOpc,
|
unsigned &AddSubOpc,
|
||||||
|
|
|
@ -246,6 +246,9 @@ private:
|
||||||
bool hasLowDefLatency(const InstrItineraryData *ItinData,
|
bool hasLowDefLatency(const InstrItineraryData *ItinData,
|
||||||
const MachineInstr *DefMI, unsigned DefIdx) const;
|
const MachineInstr *DefMI, unsigned DefIdx) const;
|
||||||
|
|
||||||
|
/// verifyInstruction - Perform target specific instruction verification.
|
||||||
|
bool verifyInstruction(const MachineInstr *MI, StringRef &ErrInfo) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Modeling special VFP / NEON fp MLA / MLS hazards.
|
/// Modeling special VFP / NEON fp MLA / MLS hazards.
|
||||||
|
|
||||||
|
@ -328,6 +331,12 @@ ARMCC::CondCodes getInstrPredicate(const MachineInstr *MI, unsigned &PredReg);
|
||||||
|
|
||||||
int getMatchingCondBranchOpcode(int Opc);
|
int getMatchingCondBranchOpcode(int Opc);
|
||||||
|
|
||||||
|
|
||||||
|
/// Map pseudo instructions that imply an 'S' bit onto real opcodes. Whether
|
||||||
|
/// the instruction is encoded with an 'S' bit is determined by the optional
|
||||||
|
/// CPSR def operand.
|
||||||
|
unsigned convertAddSubFlagsOpcode(unsigned OldOpc);
|
||||||
|
|
||||||
/// emitARMRegPlusImmediate / emitT2RegPlusImmediate - Emits a series of
|
/// emitARMRegPlusImmediate / emitT2RegPlusImmediate - Emits a series of
|
||||||
/// instructions to materializea destreg = basereg + immediate in ARM / Thumb2
|
/// instructions to materializea destreg = basereg + immediate in ARM / Thumb2
|
||||||
/// code.
|
/// code.
|
||||||
|
|
|
@ -5752,40 +5752,39 @@ ARMTargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generally, ARM instructions may be optionally encoded with a 's'
|
|
||||||
/// bit. However, some opcodes have a compact encoding that forces an implicit
|
|
||||||
/// 's' bit. List these exceptions here.
|
|
||||||
static bool hasForcedCPSRDef(const MCInstrDesc &MCID) {
|
|
||||||
switch (MCID.getOpcode()) {
|
|
||||||
case ARM::t2ADDSri:
|
|
||||||
case ARM::t2ADDSrr:
|
|
||||||
case ARM::t2ADDSrs:
|
|
||||||
case ARM::t2SUBSri:
|
|
||||||
case ARM::t2SUBSrr:
|
|
||||||
case ARM::t2SUBSrs:
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ARMTargetLowering::AdjustInstrPostInstrSelection(MachineInstr *MI,
|
void ARMTargetLowering::AdjustInstrPostInstrSelection(MachineInstr *MI,
|
||||||
SDNode *Node) const {
|
SDNode *Node) const {
|
||||||
|
const MCInstrDesc &MCID = MI->getDesc();
|
||||||
|
if (!MCID.hasPostISelHook()) {
|
||||||
|
assert(!convertAddSubFlagsOpcode(MI->getOpcode()) &&
|
||||||
|
"Pseudo flag-setting opcodes must be marked with 'hasPostISelHook'");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Adjust potentially 's' setting instructions after isel, i.e. ADC, SBC, RSB,
|
// Adjust potentially 's' setting instructions after isel, i.e. ADC, SBC, RSB,
|
||||||
// RSC. Coming out of isel, they have an implicit CPSR def, but the optional
|
// RSC. Coming out of isel, they have an implicit CPSR def, but the optional
|
||||||
// operand is still set to noreg. If needed, set the optional operand's
|
// operand is still set to noreg. If needed, set the optional operand's
|
||||||
// register to CPSR, and remove the redundant implicit def.
|
// register to CPSR, and remove the redundant implicit def.
|
||||||
|
//
|
||||||
|
// e.g. ADCS (...opt:%noreg, CPSR<imp-def>) -> ADC (... opt:CPSR<def>).
|
||||||
|
|
||||||
const MCInstrDesc &MCID = MI->getDesc();
|
// Rename pseudo opcodes.
|
||||||
|
unsigned NewOpc = convertAddSubFlagsOpcode(MI->getOpcode());
|
||||||
|
if (NewOpc) {
|
||||||
|
const ARMBaseInstrInfo *TII =
|
||||||
|
static_cast<const ARMBaseInstrInfo*>(getTargetMachine().getInstrInfo());
|
||||||
|
MI->setDesc(TII->get(NewOpc));
|
||||||
|
}
|
||||||
unsigned ccOutIdx = MCID.getNumOperands() - 1;
|
unsigned ccOutIdx = MCID.getNumOperands() - 1;
|
||||||
bool forcedCPSR = hasForcedCPSRDef(MCID);
|
|
||||||
|
|
||||||
// Any ARM instruction that sets the 's' bit should specify an optional
|
// Any ARM instruction that sets the 's' bit should specify an optional
|
||||||
// "cc_out" operand in the last operand position.
|
// "cc_out" operand in the last operand position.
|
||||||
if (!MCID.hasOptionalDef() || !MCID.OpInfo[ccOutIdx].isOptionalDef()) {
|
if (!MCID.hasOptionalDef() || !MCID.OpInfo[ccOutIdx].isOptionalDef()) {
|
||||||
assert(!forcedCPSR && "Optional cc_out operand required");
|
assert(!NewOpc && "Optional cc_out operand required");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Look for an implicit def of CPSR added by MachineInstr ctor.
|
// Look for an implicit def of CPSR added by MachineInstr ctor. Remove it
|
||||||
|
// since we already have an optional CPSR def.
|
||||||
bool definesCPSR = false;
|
bool definesCPSR = false;
|
||||||
bool deadCPSR = false;
|
bool deadCPSR = false;
|
||||||
for (unsigned i = MCID.getNumOperands(), e = MI->getNumOperands();
|
for (unsigned i = MCID.getNumOperands(), e = MI->getNumOperands();
|
||||||
|
@ -5800,20 +5799,21 @@ void ARMTargetLowering::AdjustInstrPostInstrSelection(MachineInstr *MI,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!definesCPSR) {
|
if (!definesCPSR) {
|
||||||
assert(!forcedCPSR && "Optional cc_out operand required");
|
assert(!NewOpc && "Optional cc_out operand required");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
assert(deadCPSR == !Node->hasAnyUseOfValue(1) && "inconsistent dead flag");
|
assert(deadCPSR == !Node->hasAnyUseOfValue(1) && "inconsistent dead flag");
|
||||||
|
if (deadCPSR) {
|
||||||
// If possible, select the encoding that does not set the 's' bit.
|
assert(!MI->getOperand(ccOutIdx).getReg() &&
|
||||||
if (deadCPSR && !forcedCPSR)
|
"expect uninitialized optional cc_out operand");
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this instruction was defined with an optional CPSR def and its dag node
|
||||||
|
// had a live implicit CPSR def, then activate the optional CPSR def.
|
||||||
MachineOperand &MO = MI->getOperand(ccOutIdx);
|
MachineOperand &MO = MI->getOperand(ccOutIdx);
|
||||||
MO.setReg(ARM::CPSR);
|
MO.setReg(ARM::CPSR);
|
||||||
MO.setIsDef(true);
|
MO.setIsDef(true);
|
||||||
if (deadCPSR)
|
|
||||||
MO.setIsDead();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
|
@ -1026,49 +1026,25 @@ multiclass AsI1_rbin_irs<bits<4> opcod, string opc,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// AsI1_rbin_s_is - Same as AsI1_rbin_s_is except it sets 's' bit by default.
|
/// AsI1_rbin_s_is - Same as AsI1_rbin_s_is except it sets 's' bit by default.
|
||||||
let hasPostISelHook = 1, isCodeGenOnly = 1, Defs = [CPSR] in {
|
///
|
||||||
|
/// These opcodes will be converted to the real non-S opcodes by
|
||||||
|
/// AdjustInstrPostInstrSelection after giving then an optional CPSR operand.
|
||||||
|
let hasPostISelHook = 1, isCodeGenOnly = 1, isPseudo = 1, Defs = [CPSR] in {
|
||||||
multiclass AsI1_rbin_s_is<bits<4> opcod, string opc,
|
multiclass AsI1_rbin_s_is<bits<4> opcod, string opc,
|
||||||
InstrItinClass iii, InstrItinClass iir, InstrItinClass iis,
|
InstrItinClass iii, InstrItinClass iir, InstrItinClass iis,
|
||||||
PatFrag opnode, bit Commutable = 0> {
|
PatFrag opnode, bit Commutable = 0> {
|
||||||
def ri : AsI1<opcod, (outs GPR:$Rd), (ins GPR:$Rn, so_imm:$imm), DPFrm,
|
def ri : AsI1<opcod, (outs GPR:$Rd), (ins GPR:$Rn, so_imm:$imm), DPFrm,
|
||||||
iii, opc, "\t$Rd, $Rn, $imm",
|
iii, opc, "\t$Rd, $Rn, $imm",
|
||||||
[(set GPR:$Rd, CPSR, (opnode so_imm:$imm, GPR:$Rn))]> {
|
[(set GPR:$Rd, CPSR, (opnode so_imm:$imm, GPR:$Rn))]>;
|
||||||
bits<4> Rd;
|
|
||||||
bits<4> Rn;
|
|
||||||
bits<12> imm;
|
|
||||||
let Inst{25} = 1;
|
|
||||||
let Inst{19-16} = Rn;
|
|
||||||
let Inst{15-12} = Rd;
|
|
||||||
let Inst{11-0} = imm;
|
|
||||||
}
|
|
||||||
|
|
||||||
def rr : AsI1<opcod, (outs GPR:$Rd), (ins GPR:$Rn, GPR:$Rm), DPFrm,
|
def rr : AsI1<opcod, (outs GPR:$Rd), (ins GPR:$Rn, GPR:$Rm), DPFrm,
|
||||||
iir, opc, "\t$Rd, $Rn, $Rm",
|
iir, opc, "\t$Rd, $Rn, $Rm",
|
||||||
[/* pattern left blank */]> {
|
[/* pattern left blank */]>;
|
||||||
bits<4> Rd;
|
|
||||||
bits<4> Rn;
|
|
||||||
bits<4> Rm;
|
|
||||||
let Inst{11-4} = 0b00000000;
|
|
||||||
let Inst{25} = 0;
|
|
||||||
let Inst{3-0} = Rm;
|
|
||||||
let Inst{15-12} = Rd;
|
|
||||||
let Inst{19-16} = Rn;
|
|
||||||
}
|
|
||||||
|
|
||||||
def rsi : AsI1<opcod, (outs GPR:$Rd),
|
def rsi : AsI1<opcod, (outs GPR:$Rd),
|
||||||
(ins GPR:$Rn, so_reg_imm:$shift), DPSoRegImmFrm,
|
(ins GPR:$Rn, so_reg_imm:$shift), DPSoRegImmFrm,
|
||||||
iis, opc, "\t$Rd, $Rn, $shift",
|
iis, opc, "\t$Rd, $Rn, $shift",
|
||||||
[(set GPR:$Rd, CPSR, (opnode so_reg_imm:$shift, GPR:$Rn))]> {
|
[(set GPR:$Rd, CPSR, (opnode so_reg_imm:$shift, GPR:$Rn))]>;
|
||||||
bits<4> Rd;
|
|
||||||
bits<4> Rn;
|
|
||||||
bits<12> shift;
|
|
||||||
let Inst{25} = 0;
|
|
||||||
let Inst{19-16} = Rn;
|
|
||||||
let Inst{15-12} = Rd;
|
|
||||||
let Inst{11-5} = shift{11-5};
|
|
||||||
let Inst{4} = 0;
|
|
||||||
let Inst{3-0} = shift{3-0};
|
|
||||||
}
|
|
||||||
|
|
||||||
def rsr : AsI1<opcod, (outs GPR:$Rd),
|
def rsr : AsI1<opcod, (outs GPR:$Rd),
|
||||||
(ins GPR:$Rn, so_reg_reg:$shift), DPSoRegRegFrm,
|
(ins GPR:$Rn, so_reg_reg:$shift), DPSoRegRegFrm,
|
||||||
|
@ -1090,68 +1066,28 @@ multiclass AsI1_rbin_s_is<bits<4> opcod, string opc,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// AsI1_bin_s_irs - Same as AsI1_bin_irs except it sets the 's' bit by default.
|
/// AsI1_bin_s_irs - Same as AsI1_bin_irs except it sets the 's' bit by default.
|
||||||
let hasPostISelHook = 1, isCodeGenOnly = 1, Defs = [CPSR] in {
|
///
|
||||||
|
/// These opcodes will be converted to the real non-S opcodes by
|
||||||
|
/// AdjustInstrPostInstrSelection after giving then an optional CPSR operand.
|
||||||
|
let hasPostISelHook = 1, isCodeGenOnly = 1, isPseudo = 1, Defs = [CPSR] in {
|
||||||
multiclass AsI1_bin_s_irs<bits<4> opcod, string opc,
|
multiclass AsI1_bin_s_irs<bits<4> opcod, string opc,
|
||||||
InstrItinClass iii, InstrItinClass iir, InstrItinClass iis,
|
InstrItinClass iii, InstrItinClass iir, InstrItinClass iis,
|
||||||
PatFrag opnode, bit Commutable = 0> {
|
PatFrag opnode, bit Commutable = 0> {
|
||||||
let isReMaterializable = 1 in {
|
|
||||||
def ri : AsI1<opcod, (outs GPR:$Rd), (ins GPR:$Rn, so_imm:$imm), DPFrm,
|
def ri : AsI1<opcod, (outs GPR:$Rd), (ins GPR:$Rn, so_imm:$imm), DPFrm,
|
||||||
iii, opc, "\t$Rd, $Rn, $imm",
|
iii, opc, "\t$Rd, $Rn, $imm",
|
||||||
[(set GPR:$Rd, CPSR, (opnode GPR:$Rn, so_imm:$imm))]> {
|
[(set GPR:$Rd, CPSR, (opnode GPR:$Rn, so_imm:$imm))]>;
|
||||||
bits<4> Rd;
|
|
||||||
bits<4> Rn;
|
|
||||||
bits<12> imm;
|
|
||||||
let Inst{25} = 1;
|
|
||||||
let Inst{19-16} = Rn;
|
|
||||||
let Inst{15-12} = Rd;
|
|
||||||
let Inst{11-0} = imm;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
def rr : AsI1<opcod, (outs GPR:$Rd), (ins GPR:$Rn, GPR:$Rm), DPFrm,
|
def rr : AsI1<opcod, (outs GPR:$Rd), (ins GPR:$Rn, GPR:$Rm), DPFrm,
|
||||||
iir, opc, "\t$Rd, $Rn, $Rm",
|
iir, opc, "\t$Rd, $Rn, $Rm",
|
||||||
[(set GPR:$Rd, CPSR, (opnode GPR:$Rn, GPR:$Rm))]> {
|
[(set GPR:$Rd, CPSR, (opnode GPR:$Rn, GPR:$Rm))]>;
|
||||||
bits<4> Rd;
|
|
||||||
bits<4> Rn;
|
|
||||||
bits<4> Rm;
|
|
||||||
let isCommutable = Commutable;
|
|
||||||
let Inst{25} = 0;
|
|
||||||
let Inst{19-16} = Rn;
|
|
||||||
let Inst{15-12} = Rd;
|
|
||||||
let Inst{11-4} = 0b00000000;
|
|
||||||
let Inst{3-0} = Rm;
|
|
||||||
}
|
|
||||||
def rsi : AsI1<opcod, (outs GPR:$Rd),
|
def rsi : AsI1<opcod, (outs GPR:$Rd),
|
||||||
(ins GPR:$Rn, so_reg_imm:$shift), DPSoRegImmFrm,
|
(ins GPR:$Rn, so_reg_imm:$shift), DPSoRegImmFrm,
|
||||||
iis, opc, "\t$Rd, $Rn, $shift",
|
iis, opc, "\t$Rd, $Rn, $shift",
|
||||||
[(set GPR:$Rd, CPSR, (opnode GPR:$Rn, so_reg_imm:$shift))]> {
|
[(set GPR:$Rd, CPSR, (opnode GPR:$Rn, so_reg_imm:$shift))]>;
|
||||||
bits<4> Rd;
|
|
||||||
bits<4> Rn;
|
|
||||||
bits<12> shift;
|
|
||||||
let Inst{25} = 0;
|
|
||||||
let Inst{19-16} = Rn;
|
|
||||||
let Inst{15-12} = Rd;
|
|
||||||
let Inst{11-5} = shift{11-5};
|
|
||||||
let Inst{4} = 0;
|
|
||||||
let Inst{3-0} = shift{3-0};
|
|
||||||
}
|
|
||||||
|
|
||||||
def rsr : AsI1<opcod, (outs GPR:$Rd),
|
def rsr : AsI1<opcod, (outs GPR:$Rd),
|
||||||
(ins GPR:$Rn, so_reg_reg:$shift), DPSoRegRegFrm,
|
(ins GPR:$Rn, so_reg_reg:$shift), DPSoRegRegFrm,
|
||||||
iis, opc, "\t$Rd, $Rn, $shift",
|
iis, opc, "\t$Rd, $Rn, $shift",
|
||||||
[(set GPR:$Rd, CPSR, (opnode GPR:$Rn, so_reg_reg:$shift))]> {
|
[(set GPR:$Rd, CPSR, (opnode GPR:$Rn, so_reg_reg:$shift))]>;
|
||||||
bits<4> Rd;
|
|
||||||
bits<4> Rn;
|
|
||||||
bits<12> shift;
|
|
||||||
let Inst{25} = 0;
|
|
||||||
let Inst{20} = 1;
|
|
||||||
let Inst{19-16} = Rn;
|
|
||||||
let Inst{15-12} = Rd;
|
|
||||||
let Inst{11-8} = shift{11-8};
|
|
||||||
let Inst{7} = 0;
|
|
||||||
let Inst{6-5} = shift{6-5};
|
|
||||||
let Inst{4} = 1;
|
|
||||||
let Inst{3-0} = shift{3-0};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3122,8 +3058,15 @@ defm SUB : AsI1_bin_irs<0b0010, "sub",
|
||||||
BinOpFrag<(sub node:$LHS, node:$RHS)>, "SUB">;
|
BinOpFrag<(sub node:$LHS, node:$RHS)>, "SUB">;
|
||||||
|
|
||||||
// ADD and SUB with 's' bit set.
|
// ADD and SUB with 's' bit set.
|
||||||
// FIXME: Eliminate them if we can write def : Pat patterns which defines
|
//
|
||||||
// CPSR and the implicit def of CPSR is not needed.
|
// Currently, t2ADDS/t2SUBS are pseudo opcodes that exist only in the
|
||||||
|
// selection DAG. They are "lowered" to real t2ADD/t2SUB opcodes by
|
||||||
|
// AdjustInstrPostInstrSelection where we determine whether or not to
|
||||||
|
// set the "s" bit based on CPSR liveness.
|
||||||
|
//
|
||||||
|
// FIXME: Eliminate t2ADDS/t2SUBS pseudo opcodes after adding tablegen
|
||||||
|
// support for an optional CPSR definition that corresponds to the DAG
|
||||||
|
// node's second value. We can then eliminate the implicit def of CPSR.
|
||||||
defm ADDS : AsI1_bin_s_irs<0b0100, "add",
|
defm ADDS : AsI1_bin_s_irs<0b0100, "add",
|
||||||
IIC_iALUi, IIC_iALUr, IIC_iALUsr,
|
IIC_iALUi, IIC_iALUr, IIC_iALUsr,
|
||||||
BinOpFrag<(ARMaddc node:$LHS, node:$RHS)>, 1>;
|
BinOpFrag<(ARMaddc node:$LHS, node:$RHS)>, 1>;
|
||||||
|
|
|
@ -592,7 +592,10 @@ multiclass T2I_rbin_irs<bits<4> opcod, string opc, PatFrag opnode> {
|
||||||
|
|
||||||
/// T2I_bin_s_irs - Similar to T2I_bin_irs except it sets the 's' bit so the
|
/// T2I_bin_s_irs - Similar to T2I_bin_irs except it sets the 's' bit so the
|
||||||
/// instruction modifies the CPSR register.
|
/// instruction modifies the CPSR register.
|
||||||
let hasPostISelHook = 1, isCodeGenOnly = 1, Defs = [CPSR] in {
|
///
|
||||||
|
/// These opcodes will be converted to the real non-S opcodes by
|
||||||
|
/// AdjustInstrPostInstrSelection after giving then an optional CPSR operand.
|
||||||
|
let hasPostISelHook = 1, isCodeGenOnly = 1, isPseudo = 1, Defs = [CPSR] in {
|
||||||
multiclass T2I_bin_s_irs<bits<4> opcod, string opc,
|
multiclass T2I_bin_s_irs<bits<4> opcod, string opc,
|
||||||
InstrItinClass iii, InstrItinClass iir, InstrItinClass iis,
|
InstrItinClass iii, InstrItinClass iir, InstrItinClass iis,
|
||||||
PatFrag opnode, bit Commutable = 0> {
|
PatFrag opnode, bit Commutable = 0> {
|
||||||
|
@ -600,34 +603,17 @@ multiclass T2I_bin_s_irs<bits<4> opcod, string opc,
|
||||||
def ri : T2sTwoRegImm<
|
def ri : T2sTwoRegImm<
|
||||||
(outs rGPR:$Rd), (ins GPR:$Rn, t2_so_imm:$imm), iii,
|
(outs rGPR:$Rd), (ins GPR:$Rn, t2_so_imm:$imm), iii,
|
||||||
opc, ".w\t$Rd, $Rn, $imm",
|
opc, ".w\t$Rd, $Rn, $imm",
|
||||||
[(set rGPR:$Rd, CPSR, (opnode GPR:$Rn, t2_so_imm:$imm))]> {
|
[(set rGPR:$Rd, CPSR, (opnode GPR:$Rn, t2_so_imm:$imm))]>;
|
||||||
let Inst{31-27} = 0b11110;
|
|
||||||
let Inst{25} = 0;
|
|
||||||
let Inst{24-21} = opcod;
|
|
||||||
let Inst{15} = 0;
|
|
||||||
}
|
|
||||||
// register
|
// register
|
||||||
def rr : T2sThreeReg<
|
def rr : T2sThreeReg<
|
||||||
(outs rGPR:$Rd), (ins GPR:$Rn, rGPR:$Rm), iir,
|
(outs rGPR:$Rd), (ins GPR:$Rn, rGPR:$Rm), iir,
|
||||||
opc, ".w\t$Rd, $Rn, $Rm",
|
opc, ".w\t$Rd, $Rn, $Rm",
|
||||||
[(set rGPR:$Rd, CPSR, (opnode GPR:$Rn, rGPR:$Rm))]> {
|
[(set rGPR:$Rd, CPSR, (opnode GPR:$Rn, rGPR:$Rm))]>;
|
||||||
let isCommutable = Commutable;
|
|
||||||
let Inst{31-27} = 0b11101;
|
|
||||||
let Inst{26-25} = 0b01;
|
|
||||||
let Inst{24-21} = opcod;
|
|
||||||
let Inst{14-12} = 0b000; // imm3
|
|
||||||
let Inst{7-6} = 0b00; // imm2
|
|
||||||
let Inst{5-4} = 0b00; // type
|
|
||||||
}
|
|
||||||
// shifted register
|
// shifted register
|
||||||
def rs : T2sTwoRegShiftedReg<
|
def rs : T2sTwoRegShiftedReg<
|
||||||
(outs rGPR:$Rd), (ins GPR:$Rn, t2_so_reg:$ShiftedRm), iis,
|
(outs rGPR:$Rd), (ins GPR:$Rn, t2_so_reg:$ShiftedRm), iis,
|
||||||
opc, ".w\t$Rd, $Rn, $ShiftedRm",
|
opc, ".w\t$Rd, $Rn, $ShiftedRm",
|
||||||
[(set rGPR:$Rd, CPSR, (opnode GPR:$Rn, t2_so_reg:$ShiftedRm))]> {
|
[(set rGPR:$Rd, CPSR, (opnode GPR:$Rn, t2_so_reg:$ShiftedRm))]>;
|
||||||
let Inst{31-27} = 0b11101;
|
|
||||||
let Inst{26-25} = 0b01;
|
|
||||||
let Inst{24-21} = opcod;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -738,27 +724,21 @@ multiclass T2I_adde_sube_irs<bits<4> opcod, string opc, PatFrag opnode,
|
||||||
|
|
||||||
/// T2I_rbin_s_is - Same as T2I_rbin_irs except sets 's' bit and the register
|
/// T2I_rbin_s_is - Same as T2I_rbin_irs except sets 's' bit and the register
|
||||||
/// version is not needed since this is only for codegen.
|
/// version is not needed since this is only for codegen.
|
||||||
let hasPostISelHook = 1, isCodeGenOnly = 1, Defs = [CPSR] in {
|
///
|
||||||
|
/// These opcodes will be converted to the real non-S opcodes by
|
||||||
|
/// AdjustInstrPostInstrSelection after giving then an optional CPSR operand.
|
||||||
|
let hasPostISelHook = 1, isCodeGenOnly = 1, isPseudo = 1, Defs = [CPSR] in {
|
||||||
multiclass T2I_rbin_s_is<bits<4> opcod, string opc, PatFrag opnode> {
|
multiclass T2I_rbin_s_is<bits<4> opcod, string opc, PatFrag opnode> {
|
||||||
// shifted imm
|
// shifted imm
|
||||||
def ri : T2sTwoRegImm<
|
def ri : T2sTwoRegImm<
|
||||||
(outs rGPR:$Rd), (ins rGPR:$Rn, t2_so_imm:$imm), IIC_iALUi,
|
(outs rGPR:$Rd), (ins rGPR:$Rn, t2_so_imm:$imm), IIC_iALUi,
|
||||||
opc, ".w\t$Rd, $Rn, $imm",
|
opc, ".w\t$Rd, $Rn, $imm",
|
||||||
[(set rGPR:$Rd, CPSR, (opnode t2_so_imm:$imm, rGPR:$Rn))]> {
|
[(set rGPR:$Rd, CPSR, (opnode t2_so_imm:$imm, rGPR:$Rn))]>;
|
||||||
let Inst{31-27} = 0b11110;
|
|
||||||
let Inst{25} = 0;
|
|
||||||
let Inst{24-21} = opcod;
|
|
||||||
let Inst{15} = 0;
|
|
||||||
}
|
|
||||||
// shifted register
|
// shifted register
|
||||||
def rs : T2sTwoRegShiftedReg<
|
def rs : T2sTwoRegShiftedReg<
|
||||||
(outs rGPR:$Rd), (ins rGPR:$Rn, t2_so_reg:$ShiftedRm),
|
(outs rGPR:$Rd), (ins rGPR:$Rn, t2_so_reg:$ShiftedRm),
|
||||||
IIC_iALUsi, opc, "\t$Rd, $Rn, $ShiftedRm",
|
IIC_iALUsi, opc, "\t$Rd, $Rn, $ShiftedRm",
|
||||||
[(set rGPR:$Rd, CPSR, (opnode t2_so_reg:$ShiftedRm, rGPR:$Rn))]> {
|
[(set rGPR:$Rd, CPSR, (opnode t2_so_reg:$ShiftedRm, rGPR:$Rn))]>;
|
||||||
let Inst{31-27} = 0b11101;
|
|
||||||
let Inst{26-25} = 0b01;
|
|
||||||
let Inst{24-21} = opcod;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1837,8 +1817,15 @@ defm t2SUB : T2I_bin_ii12rs<0b101, "sub",
|
||||||
BinOpFrag<(sub node:$LHS, node:$RHS)>>;
|
BinOpFrag<(sub node:$LHS, node:$RHS)>>;
|
||||||
|
|
||||||
// ADD and SUB with 's' bit set. No 12-bit immediate (T4) variants.
|
// ADD and SUB with 's' bit set. No 12-bit immediate (T4) variants.
|
||||||
// FIXME: Eliminate them if we can write def : Pat patterns which defines
|
//
|
||||||
// CPSR and the implicit def of CPSR is not needed.
|
// Currently, t2ADDS/t2SUBS are pseudo opcodes that exist only in the
|
||||||
|
// selection DAG. They are "lowered" to real t2ADD/t2SUB opcodes by
|
||||||
|
// AdjustInstrPostInstrSelection where we determine whether or not to
|
||||||
|
// set the "s" bit based on CPSR liveness.
|
||||||
|
//
|
||||||
|
// FIXME: Eliminate t2ADDS/t2SUBS pseudo opcodes after adding tablegen
|
||||||
|
// support for an optional CPSR definition that corresponds to the DAG
|
||||||
|
// node's second value. We can then eliminate the implicit def of CPSR.
|
||||||
defm t2ADDS : T2I_bin_s_irs <0b1000, "add",
|
defm t2ADDS : T2I_bin_s_irs <0b1000, "add",
|
||||||
IIC_iALUi, IIC_iALUr, IIC_iALUsi,
|
IIC_iALUi, IIC_iALUr, IIC_iALUsi,
|
||||||
BinOpFrag<(ARMaddc node:$LHS, node:$RHS)>, 1>;
|
BinOpFrag<(ARMaddc node:$LHS, node:$RHS)>, 1>;
|
||||||
|
|
Loading…
Reference in New Issue