diff options
Diffstat (limited to 'llvm/lib/Target/ARM')
| -rw-r--r-- | llvm/lib/Target/ARM/ARMISelLowering.cpp | 73 | ||||
| -rw-r--r-- | llvm/lib/Target/ARM/ARMInstrInfo.td | 8 | ||||
| -rw-r--r-- | llvm/lib/Target/ARM/ARMInstrThumb2.td | 6 |
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", |

