diff options
author | Andrew Trick <atrick@apple.com> | 2011-09-21 02:20:46 +0000 |
---|---|---|
committer | Andrew Trick <atrick@apple.com> | 2011-09-21 02:20:46 +0000 |
commit | 3be654f8082dcbdff011a6716a7c90486e28fc9e (patch) | |
tree | c8ed3778b0094ee060135ae967ad30fd478c7635 /lib/Target/ARM/ARMISelLowering.cpp | |
parent | e23dc9c0ef50b0a1934c04c1786f3a0478d62f41 (diff) |
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.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@140228 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Target/ARM/ARMISelLowering.cpp')
-rw-r--r-- | lib/Target/ARM/ARMISelLowering.cpp | 52 |
1 files changed, 26 insertions, 26 deletions
diff --git a/lib/Target/ARM/ARMISelLowering.cpp b/lib/Target/ARM/ARMISelLowering.cpp index 28860911d6..697af66ec9 100644 --- a/lib/Target/ARM/ARMISelLowering.cpp +++ b/lib/Target/ARM/ARMISelLowering.cpp @@ -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, 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, // 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 // 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; - bool forcedCPSR = hasForcedCPSRDef(MCID); // Any ARM instruction that sets the 's' bit should specify an optional // "cc_out" operand in the last operand position. if (!MCID.hasOptionalDef() || !MCID.OpInfo[ccOutIdx].isOptionalDef()) { - assert(!forcedCPSR && "Optional cc_out operand required"); + assert(!NewOpc && "Optional cc_out operand required"); 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 deadCPSR = false; for (unsigned i = MCID.getNumOperands(), e = MI->getNumOperands(); @@ -5800,20 +5799,21 @@ void ARMTargetLowering::AdjustInstrPostInstrSelection(MachineInstr *MI, } } if (!definesCPSR) { - assert(!forcedCPSR && "Optional cc_out operand required"); + assert(!NewOpc && "Optional cc_out operand required"); return; } assert(deadCPSR == !Node->hasAnyUseOfValue(1) && "inconsistent dead flag"); - - // If possible, select the encoding that does not set the 's' bit. - if (deadCPSR && !forcedCPSR) + if (deadCPSR) { + assert(!MI->getOperand(ccOutIdx).getReg() && + "expect uninitialized optional cc_out operand"); 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); MO.setReg(ARM::CPSR); MO.setIsDef(true); - if (deadCPSR) - MO.setIsDead(); } //===----------------------------------------------------------------------===// |