summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Target/ARM
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Target/ARM')
-rw-r--r--llvm/lib/Target/ARM/ARMISelLowering.cpp73
-rw-r--r--llvm/lib/Target/ARM/ARMInstrInfo.td8
-rw-r--r--llvm/lib/Target/ARM/ARMInstrThumb2.td6
3 files changed, 63 insertions, 24 deletions
diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp
index 7a866585844..28860911d66 100644
--- a/llvm/lib/Target/ARM/ARMISelLowering.cpp
+++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp
@@ -5752,27 +5752,68 @@ 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 {
- // 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 not filled in. If the carry bit is used, then change
- // the optional operand to CPSR. Otherwise, remove the CPSR implicit def.
+ // 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.
+
const MCInstrDesc &MCID = MI->getDesc();
- if (Node->hasAnyUseOfValue(1)) {
- MachineOperand &MO = MI->getOperand(MCID.getNumOperands() - 1);
- MO.setReg(ARM::CPSR);
- MO.setIsDef(true);
- } else {
- for (unsigned i = MCID.getNumOperands(), e = MI->getNumOperands();
- i != e; ++i) {
- const MachineOperand &MO = MI->getOperand(i);
- if (MO.isReg() && MO.isDef() && MO.getReg() == ARM::CPSR) {
- MI->RemoveOperand(i);
- break;
- }
+ 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");
+ return;
+ }
+ // Look for an implicit def of CPSR added by MachineInstr ctor.
+ bool definesCPSR = false;
+ bool deadCPSR = false;
+ for (unsigned i = MCID.getNumOperands(), e = MI->getNumOperands();
+ i != e; ++i) {
+ const MachineOperand &MO = MI->getOperand(i);
+ if (MO.isReg() && MO.isDef() && MO.getReg() == ARM::CPSR) {
+ definesCPSR = true;
+ if (MO.isDead())
+ deadCPSR = true;
+ MI->RemoveOperand(i);
+ break;
}
}
+ if (!definesCPSR) {
+ assert(!forcedCPSR && "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)
+ return;
+
+ MachineOperand &MO = MI->getOperand(ccOutIdx);
+ MO.setReg(ARM::CPSR);
+ MO.setIsDef(true);
+ if (deadCPSR)
+ MO.setIsDead();
}
//===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/ARM/ARMInstrInfo.td b/llvm/lib/Target/ARM/ARMInstrInfo.td
index 818735561c5..1ad84f2c166 100644
--- a/llvm/lib/Target/ARM/ARMInstrInfo.td
+++ b/llvm/lib/Target/ARM/ARMInstrInfo.td
@@ -1026,7 +1026,7 @@ 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.
-let hasPostISelHook = 1, isCodeGenOnly = 1, Defs = [CPSR] in {
+let isCodeGenOnly = 1, Defs = [CPSR] in {
multiclass AsI1_rbin_s_is<bits<4> opcod, string opc,
InstrItinClass iii, InstrItinClass iir, InstrItinClass iis,
PatFrag opnode, bit Commutable = 0> {
@@ -1090,7 +1090,7 @@ 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.
-let hasPostISelHook = 1, isCodeGenOnly = 1, Defs = [CPSR] in {
+let isCodeGenOnly = 1, Defs = [CPSR] in {
multiclass AsI1_bin_s_irs<bits<4> opcod, string opc,
InstrItinClass iii, InstrItinClass iir, InstrItinClass iis,
PatFrag opnode, bit Commutable = 0> {
@@ -1278,7 +1278,7 @@ class AI_exta_rrot_np<bits<8> opcod, string opc>
/// AI1_adde_sube_irs - Define instructions and patterns for adde and sube.
multiclass AI1_adde_sube_irs<bits<4> opcod, string opc, PatFrag opnode,
string baseOpc, bit Commutable = 0> {
- let hasPostISelHook = 1, Defs = [CPSR], Uses = [CPSR] in {
+ let Defs = [CPSR], Uses = [CPSR] in {
def ri : AsI1<opcod, (outs GPR:$Rd), (ins GPR:$Rn, so_imm:$imm),
DPFrm, IIC_iALUi, opc, "\t$Rd, $Rn, $imm",
[(set GPR:$Rd, CPSR, (opnode GPR:$Rn, so_imm:$imm, CPSR))]>,
@@ -1366,7 +1366,7 @@ multiclass AI1_adde_sube_irs<bits<4> opcod, string opc, PatFrag opnode,
/// AI1_rsc_irs - Define instructions and patterns for rsc
multiclass AI1_rsc_irs<bits<4> opcod, string opc, PatFrag opnode,
string baseOpc> {
- let hasPostISelHook = 1, Defs = [CPSR], Uses = [CPSR] in {
+ let Defs = [CPSR], Uses = [CPSR] in {
def ri : AsI1<opcod, (outs GPR:$Rd), (ins GPR:$Rn, so_imm:$imm),
DPFrm, IIC_iALUi, opc, "\t$Rd, $Rn, $imm",
[(set GPR:$Rd, CPSR, (opnode so_imm:$imm, GPR:$Rn, CPSR))]>,
diff --git a/llvm/lib/Target/ARM/ARMInstrThumb2.td b/llvm/lib/Target/ARM/ARMInstrThumb2.td
index 4ed58a42b72..ddc4441f039 100644
--- a/llvm/lib/Target/ARM/ARMInstrThumb2.td
+++ b/llvm/lib/Target/ARM/ARMInstrThumb2.td
@@ -592,7 +592,7 @@ 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
/// instruction modifies the CPSR register.
-let hasPostISelHook = 1, isCodeGenOnly = 1, Defs = [CPSR] in {
+let isCodeGenOnly = 1, Defs = [CPSR] in {
multiclass T2I_bin_s_irs<bits<4> opcod, string opc,
InstrItinClass iii, InstrItinClass iir, InstrItinClass iis,
PatFrag opnode, bit Commutable = 0> {
@@ -738,7 +738,7 @@ 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
/// version is not needed since this is only for codegen.
-let hasPostISelHook = 1, isCodeGenOnly = 1, Defs = [CPSR] in {
+let isCodeGenOnly = 1, Defs = [CPSR] in {
multiclass T2I_rbin_s_is<bits<4> opcod, string opc, PatFrag opnode> {
// shifted imm
def ri : T2sTwoRegImm<
@@ -1846,12 +1846,10 @@ defm t2SUBS : T2I_bin_s_irs <0b1101, "sub",
IIC_iALUi, IIC_iALUr, IIC_iALUsi,
BinOpFrag<(ARMsubc node:$LHS, node:$RHS)>>;
-let hasPostISelHook = 1 in {
defm t2ADC : T2I_adde_sube_irs<0b1010, "adc",
BinOpWithFlagFrag<(ARMadde node:$LHS, node:$RHS, node:$FLAG)>, 1>;
defm t2SBC : T2I_adde_sube_irs<0b1011, "sbc",
BinOpWithFlagFrag<(ARMsube node:$LHS, node:$RHS, node:$FLAG)>>;
-}
// RSB
defm t2RSB : T2I_rbin_irs <0b1110, "rsb",
OpenPOWER on IntegriCloud