Index: include/llvm/CodeGen/MachineInstr.h =================================================================== --- include/llvm/CodeGen/MachineInstr.h +++ include/llvm/CodeGen/MachineInstr.h @@ -614,7 +614,6 @@ /// are not marking copies from and to the same register class with this flag. bool isAsCheapAsAMove(QueryType Type = AllInBundle) const { // Only returns true for a bundle if all bundled instructions are cheap. - // FIXME: This probably requires a target hook. return hasProperty(MCID::CheapAsAMove, Type); } Index: include/llvm/Target/TargetInstrInfo.h =================================================================== --- include/llvm/Target/TargetInstrInfo.h +++ include/llvm/Target/TargetInstrInfo.h @@ -200,6 +200,15 @@ unsigned &Size, unsigned &Offset, const TargetMachine *TM) const; + /// isAsCheapAsAMove - Return true if the instruction is as cheap as a move + /// instruction. + /// + /// Targets for different archs need to override this, and different u-archs + /// can also be finely tuned inside. + virtual bool isAsCheapAsAMove(const MachineInstr *MI) const { + return MI->isAsCheapAsAMove(); + } + /// reMaterialize - Re-issue the specified 'original' instruction at the /// specific location targeting a new destination register. /// The register in Orig->getOperand(0).getReg() will be substituted by Index: lib/CodeGen/RegisterCoalescer.cpp =================================================================== --- lib/CodeGen/RegisterCoalescer.cpp +++ lib/CodeGen/RegisterCoalescer.cpp @@ -751,7 +751,7 @@ IsDefCopy = true; return false; } - if (!DefMI->isAsCheapAsAMove()) + if (!TII->isAsCheapAsAMove(DefMI)) return false; if (!TII->isTriviallyReMaterializable(DefMI, AA)) return false; Index: lib/Target/AArch64/AArch64InstrFormats.td =================================================================== --- lib/Target/AArch64/AArch64InstrFormats.td +++ lib/Target/AArch64/AArch64InstrFormats.td @@ -1612,7 +1612,7 @@ multiclass AddSub { - let hasSideEffects = 0 in { + let hasSideEffects = 0, isReMaterializable = 1 in { // Add/Subtract immediate def Wri : BaseAddSubImm { @@ -1678,7 +1678,7 @@ } multiclass AddSubS { - let isCompare = 1, Defs = [NZCV] in { + let isCompare = 1, Defs = [NZCV], isReMaterializable = 1 in { // Add/Subtract immediate def Wri : BaseAddSubImm { @@ -1935,7 +1935,7 @@ : InstAlias; -let AddedComplexity = 6 in +let AddedComplexity = 6, isReMaterializable = 1 in multiclass LogicalImm opc, string mnemonic, SDNode OpNode> { def Wri : BaseLogicalImm opc, string mnemonic, SDNode OpNode> { - let isCompare = 1, Defs = [NZCV] in { + let isCompare = 1, Defs = [NZCV], isReMaterializable = 1 in { def Wri : BaseLogicalImm { let Inst{31} = 0; @@ -1972,8 +1972,10 @@ // Split from LogicalImm as not all instructions have both. multiclass LogicalReg opc, bit N, string mnemonic, SDPatternOperator OpNode> { + let isReMaterializable = 1 in { def Wrr : BaseLogicalRegPseudo; def Xrr : BaseLogicalRegPseudo; + } def Wrs : BaseLogicalSReg opc, bit N, string mnemonic, SDPatternOperator OpNode = null_frag> { - let Defs = [NZCV], mayLoad = 0, mayStore = 0, hasSideEffects = 0 in { + let Defs = [NZCV], mayLoad = 0, mayStore = 0, hasSideEffects = 0, + isReMaterializable = 1 in { def Wrr : BaseLogicalRegPseudo; def Xrr : BaseLogicalRegPseudo; Index: lib/Target/AArch64/AArch64InstrInfo.h =================================================================== --- lib/Target/AArch64/AArch64InstrInfo.h +++ lib/Target/AArch64/AArch64InstrInfo.h @@ -46,6 +46,8 @@ unsigned GetInstSizeInBytes(const MachineInstr *MI) const; + bool isAsCheapAsAMove(const MachineInstr *MI) const override; + bool isCoalescableExtInstr(const MachineInstr &MI, unsigned &SrcReg, unsigned &DstReg, unsigned &SubIdx) const override; Index: lib/Target/AArch64/AArch64InstrInfo.cpp =================================================================== --- lib/Target/AArch64/AArch64InstrInfo.cpp +++ lib/Target/AArch64/AArch64InstrInfo.cpp @@ -541,6 +541,66 @@ CC); } +// FIXME: this implementation should be u-arch dependent, so a u-arch target +// hook should be introduced here in future. +bool AArch64InstrInfo::isAsCheapAsAMove(const MachineInstr *MI) const { + const MachineBasicBlock *MBB = MI->getParent(); + assert(MBB && "Can't get MachineBasicBlock here"); + const MachineFunction *MF = MBB->getParent(); + assert(MF && "Can't get MachineFunction here"); + const TargetMachine *TM = &MF->getTarget(); + + if (TM->getTargetCPU() == "cortex-a57" || + TM->getTargetCPU() == "cortex-a53") { + switch (MI->getOpcode()) { + default: + return false; + + // add/sub on register without shift + case AArch64::ADDWri: + case AArch64::ADDXri: + case AArch64::SUBWri: + case AArch64::SUBXri: + case AArch64::ADDSWri: + case AArch64::ADDSXri: + case AArch64::SUBSWri: + case AArch64::SUBSXri: + if (MI->getOperand(2).getImm() != 0) + return false; + else + return true; + + // logical ops on immediate + case AArch64::ANDSWri: + case AArch64::ANDSXri: + case AArch64::ANDWri: + case AArch64::ANDXri: + case AArch64::EORWri: + case AArch64::EORXri: + case AArch64::ORRWri: + case AArch64::ORRXri: + return true; + + // logical ops on register without shift + case AArch64::ANDWrr: + case AArch64::ANDXrr: + case AArch64::BICWrr: + case AArch64::BICXrr: + case AArch64::EONWrr: + case AArch64::EONXrr: + case AArch64::EORWrr: + case AArch64::EORXrr: + case AArch64::ORNWrr: + case AArch64::ORNXrr: + case AArch64::ORRWrr: + case AArch64::ORRXrr: + return true; + } + } + + return MI->isAsCheapAsAMove(); +} + bool AArch64InstrInfo::isCoalescableExtInstr(const MachineInstr &MI, unsigned &SrcReg, unsigned &DstReg, unsigned &SubIdx) const { Index: test/CodeGen/AArch64/remat.ll =================================================================== --- /dev/null +++ test/CodeGen/AArch64/remat.ll @@ -0,0 +1,16 @@ +; RUN: llc -mtriple=aarch64-linux-gnuabi -mcpu=cortex-a57 -o - %s | FileCheck %s +; RUN: llc -mtriple=aarch64-linux-gnuabi -mcpu=cortex-a53 -o - %s | FileCheck %s + +%X = type { i64, i64, i64 } +declare void @f(%X*) +define void @t() { +entry: + %tmp = alloca %X + call void @f(%X* %tmp) +; CHECK: add x0, sp, #8 +; CHECK-NEXT-NOT: mov + call void @f(%X* %tmp) +; CHECK: add x0, sp, #8 +; CHECK-NEXT-NOT: mov + ret void +}