Index: llvm/include/llvm/CodeGen/GlobalISel/Utils.h =================================================================== --- llvm/include/llvm/CodeGen/GlobalISel/Utils.h +++ llvm/include/llvm/CodeGen/GlobalISel/Utils.h @@ -144,6 +144,13 @@ MachineInstr *getDefIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI); +/// Find the source register for \p Reg, folding away any trivial copies. It +/// will be an output register of the instruction that getDefIgnoringCopies +/// returns. May return an invalid register if \p Reg is not a generic virtual +/// register. +Register getSrcRegIgnoringCopies(Register Reg, + const MachineRegisterInfo &MRI); + /// Returns an APFloat from Val converted to the appropriate size. APFloat getAPFloatFromSize(double Val, unsigned Size); Index: llvm/lib/CodeGen/GlobalISel/Utils.cpp =================================================================== --- llvm/lib/CodeGen/GlobalISel/Utils.cpp +++ llvm/lib/CodeGen/GlobalISel/Utils.cpp @@ -300,20 +300,42 @@ return MI->getOperand(1).getFPImm(); } -llvm::MachineInstr *llvm::getDefIgnoringCopies(Register Reg, - const MachineRegisterInfo &MRI) { +struct DefinitionAndSourceRegister { + llvm::MachineInstr *MI; + Register Reg; +}; + +static llvm::Optional getDefSrcRegIgnoringCopies( + Register Reg, + const MachineRegisterInfo &MRI) { + Register DefSrcReg = Reg; auto *DefMI = MRI.getVRegDef(Reg); auto DstTy = MRI.getType(DefMI->getOperand(0).getReg()); if (!DstTy.isValid()) - return nullptr; + return None; while (DefMI->getOpcode() == TargetOpcode::COPY) { Register SrcReg = DefMI->getOperand(1).getReg(); auto SrcTy = MRI.getType(SrcReg); if (!SrcTy.isValid() || SrcTy != DstTy) break; DefMI = MRI.getVRegDef(SrcReg); + DefSrcReg = SrcReg; } - return DefMI; + return DefinitionAndSourceRegister{ DefMI, DefSrcReg }; +} + +llvm::MachineInstr *llvm::getDefIgnoringCopies(Register Reg, + const MachineRegisterInfo &MRI) { + Optional DefSrcReg = + getDefSrcRegIgnoringCopies(Reg, MRI); + return DefSrcReg ? DefSrcReg->MI : nullptr; +} + +Register llvm::getSrcRegIgnoringCopies(Register Reg, + const MachineRegisterInfo &MRI) { + Optional DefSrcReg = + getDefSrcRegIgnoringCopies(Reg, MRI); + return DefSrcReg ? DefSrcReg->Reg : Register(); } llvm::MachineInstr *llvm::getOpcodeDef(unsigned Opcode, Register Reg, Index: llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp =================================================================== --- llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp +++ llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp @@ -1575,10 +1575,9 @@ // G_STORE %x:gpr(s32) // // And then continue the selection process normally. - MachineInstr *Def = getDefIgnoringCopies(I.getOperand(0).getReg(), MRI); - if (!Def) + Register DefDstReg = getSrcRegIgnoringCopies(I.getOperand(0).getReg(), MRI); + if (!DefDstReg.isValid()) return false; - Register DefDstReg = Def->getOperand(0).getReg(); LLT DefDstTy = MRI.getType(DefDstReg); Register StoreSrcReg = I.getOperand(0).getReg(); LLT StoreSrcTy = MRI.getType(StoreSrcReg); Index: llvm/test/CodeGen/AArch64/GlobalISel/contract-store.mir =================================================================== --- llvm/test/CodeGen/AArch64/GlobalISel/contract-store.mir +++ llvm/test/CodeGen/AArch64/GlobalISel/contract-store.mir @@ -7,6 +7,8 @@ define void @contract_s64_fpr(i64* %addr) { ret void } define void @contract_s32_fpr(i32* %addr) { ret void } define void @contract_s16_fpr(i16* %addr) { ret void } + define void @contract_g_unmerge_values_first(i16* %addr) { ret void } + define void @contract_g_unmerge_values_second(i16* %addr) { ret void } ... --- name: contract_s64_gpr @@ -87,3 +89,41 @@ %1:fpr(s16) = COPY $h1 %2:gpr(s16) = COPY %1 G_STORE %2:gpr(s16), %0 :: (store 2 into %ir.addr) +... +--- +name: contract_g_unmerge_values_first +legalized: true +regBankSelected: true +body: | + bb.0: + liveins: $x0, $x1 + ; CHECK-LABEL: name: contract_g_unmerge_values_first + ; CHECK: [[COPY:%[0-9]+]]:gpr64sp = COPY $x0 + ; CHECK: [[LOAD:%[0-9]+]]:fpr128 = LDRQui [[COPY]], 0 + ; CHECK: [[COPY1:%[0-9]+]]:fpr64 = COPY [[LOAD]].dsub + ; CHECK: STRDui [[COPY1]], [[COPY]], 0 :: (store 8 into %ir.addr) + %0:gpr(p0) = COPY $x0 + %1:fpr(<2 x s64>) = G_LOAD %0:gpr(p0) :: (dereferenceable load 16 from %ir.addr) + %2:fpr(s64), %3:fpr(s64) = G_UNMERGE_VALUES %1:fpr(<2 x s64>) + %4:gpr(s64) = COPY %2 + %5:gpr(s64) = COPY %3 + G_STORE %4:gpr(s64), %0 :: (store 8 into %ir.addr) +... +--- +name: contract_g_unmerge_values_second +legalized: true +regBankSelected: true +body: | + bb.0: + liveins: $x0, $x1 + ; CHECK-LABEL: name: contract_g_unmerge_values_second + ; CHECK: [[COPY:%[0-9]+]]:gpr64sp = COPY $x0 + ; CHECK: [[LOAD:%[0-9]+]]:fpr128 = LDRQui [[COPY]], 0 + ; CHECK: [[COPY1:%[0-9]+]]:fpr64 = CPYi64 [[LOAD]], 1 + ; CHECK: STRDui [[COPY1]], [[COPY]], 0 :: (store 8 into %ir.addr) + %0:gpr(p0) = COPY $x0 + %1:fpr(<2 x s64>) = G_LOAD %0:gpr(p0) :: (dereferenceable load 16 from %ir.addr) + %2:fpr(s64), %3:fpr(s64) = G_UNMERGE_VALUES %1:fpr(<2 x s64>) + %4:gpr(s64) = COPY %2 + %5:gpr(s64) = COPY %3 + G_STORE %5:gpr(s64), %0 :: (store 8 into %ir.addr)