diff --git a/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h b/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h --- a/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h @@ -43,6 +43,11 @@ bool IsPre; }; +struct PtrAddChain { + int64_t Imm; + Register Base; +}; + class CombinerHelper { protected: MachineIRBuilder &Builder; @@ -170,6 +175,9 @@ /// $whatever = COPY $addr bool tryCombineMemCpyFamily(MachineInstr &MI, unsigned MaxLen = 0); + bool matchPtrAddImmedChain(MachineInstr &MI, PtrAddChain &MatchInfo); + bool applyPtrAddImmedChain(MachineInstr &MI, PtrAddChain &MatchInfo); + /// Try to transform \p MI by using all of the above /// combine functions. Returns true if changed. bool tryCombine(MachineInstr &MI); diff --git a/llvm/include/llvm/Target/GlobalISel/Combine.td b/llvm/include/llvm/Target/GlobalISel/Combine.td --- a/llvm/include/llvm/Target/GlobalISel/Combine.td +++ b/llvm/include/llvm/Target/GlobalISel/Combine.td @@ -129,4 +129,12 @@ [{ return Helper.matchElideBrByInvertingCond(*${root}); }]), (apply [{ Helper.applyElideBrByInvertingCond(*${root}); }])>; -def all_combines : GICombineGroup<[trivial_combines, combines_for_extload, combine_indexed_load_store]>; +def ptr_add_immed_matchdata : GIDefMatchData<"PtrAddChain">; +def ptr_add_immed_chain : GICombineRule< + (defs root:$d, ptr_add_immed_matchdata:$matchinfo), + (match (wip_match_opcode G_PTR_ADD):$d, + [{ return Helper.matchPtrAddImmedChain(*${d}, ${matchinfo}); }]), + (apply [{ Helper.applyPtrAddImmedChain(*${d}, ${matchinfo}); }])>; + +def all_combines : GICombineGroup<[trivial_combines, ptr_add_immed_chain, + combines_for_extload, combine_indexed_load_store]>; diff --git a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp --- a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp +++ b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp @@ -1340,6 +1340,52 @@ return false; } +bool CombinerHelper::matchPtrAddImmedChain(MachineInstr &MI, + PtrAddChain &MatchInfo) { + // We're trying to match the following pattern: + // %t1 = G_PTR_ADD %base, G_CONSTANT imm1 + // %root = G_PTR_ADD %t1, G_CONSTANT imm2 + // --> + // %root = G_PTR_ADD %base, G_CONSTANT (imm1 + imm2) + + if (MI.getOpcode() != TargetOpcode::G_PTR_ADD) + return false; + + Register Add2 = MI.getOperand(1).getReg(); + Register Imm1 = MI.getOperand(2).getReg(); + auto MaybeImmVal = getConstantVRegValWithLookThrough(Imm1, MRI); + if (!MaybeImmVal) + return false; + + MachineInstr *Add2Def = MRI.getUniqueVRegDef(Add2); + if (!Add2Def || Add2Def->getOpcode() != TargetOpcode::G_PTR_ADD) + return false; + + Register Base = Add2Def->getOperand(1).getReg(); + Register Imm2 = Add2Def->getOperand(2).getReg(); + auto MaybeImm2Val = getConstantVRegValWithLookThrough(Imm2, MRI); + if (!MaybeImm2Val) + return false; + + // Pass the combined immediate to the apply function. + MatchInfo.Imm = MaybeImmVal->Value + MaybeImm2Val->Value; + MatchInfo.Base = Base; + return true; +} + +bool CombinerHelper::applyPtrAddImmedChain(MachineInstr &MI, + PtrAddChain &MatchInfo) { + assert(MI.getOpcode() == TargetOpcode::G_PTR_ADD && "Expected G_PTR_ADD"); + MachineIRBuilder MIB(MI); + LLT OffsetTy = MRI.getType(MI.getOperand(2).getReg()); + auto NewOffset = MIB.buildConstant(OffsetTy, MatchInfo.Imm); + Observer.changingInstr(MI); + MI.getOperand(1).setReg(MatchInfo.Base); + MI.getOperand(2).setReg(NewOffset.getReg(0)); + Observer.changedInstr(MI); + return true; +} + bool CombinerHelper::tryCombine(MachineInstr &MI) { if (tryCombineCopy(MI)) return true; diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/prelegalizercombiner-ptradd-chain.mir b/llvm/test/CodeGen/AArch64/GlobalISel/prelegalizercombiner-ptradd-chain.mir new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/GlobalISel/prelegalizercombiner-ptradd-chain.mir @@ -0,0 +1,72 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py +# RUN: llc -mtriple aarch64-apple-ios -run-pass=aarch64-prelegalizer-combiner %s -o - -verify-machineinstrs | FileCheck %s + +# Check that we fold two adds of constant offsets with G_PTR_ADD into a single G_PTR_ADD. +--- +name: ptradd_chain +tracksRegLiveness: true +body: | + bb.1: + liveins: $x0 + + ; CHECK-LABEL: name: ptradd_chain + ; CHECK: liveins: $x0 + ; CHECK: [[COPY:%[0-9]+]]:_(p0) = COPY $x0 + ; CHECK: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 16 + ; CHECK: [[PTR_ADD:%[0-9]+]]:_(p0) = G_PTR_ADD [[COPY]], [[C]](s64) + ; CHECK: $x0 = COPY [[PTR_ADD]](p0) + ; CHECK: RET_ReallyLR implicit $x0 + %0:_(p0) = COPY $x0 + %1:_(s64) = G_CONSTANT i64 4 + %2:_(s64) = G_CONSTANT i64 12 + %3:_(p0) = G_PTR_ADD %0(p0), %1 + %4:_(p0) = G_PTR_ADD %3(p0), %2 + $x0 = COPY %4(p0) + RET_ReallyLR implicit $x0 +... +--- +name: ptradd_chain_2 +tracksRegLiveness: true +body: | + bb.1: + liveins: $x0 + ; CHECK-LABEL: name: ptradd_chain_2 + ; CHECK: liveins: $x0 + ; CHECK: [[COPY:%[0-9]+]]:_(p0) = COPY $x0 + ; CHECK: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 28 + ; CHECK: [[PTR_ADD:%[0-9]+]]:_(p0) = G_PTR_ADD [[COPY]], [[C]](s64) + ; CHECK: $x0 = COPY [[PTR_ADD]](p0) + ; CHECK: RET_ReallyLR implicit $x0 + %0:_(p0) = COPY $x0 + %1:_(s64) = G_CONSTANT i64 4 + %2:_(s64) = G_CONSTANT i64 12 + %3:_(p0) = G_PTR_ADD %0(p0), %1 + %4:_(p0) = G_PTR_ADD %3(p0), %2 + %5:_(p0) = G_PTR_ADD %4(p0), %2 + $x0 = COPY %5(p0) + RET_ReallyLR implicit $x0 +... +--- +name: ptradd_chain_lookthough +tracksRegLiveness: true +body: | + bb.1: + liveins: $x0 + ; CHECK-LABEL: name: ptradd_chain_lookthough + ; CHECK: liveins: $x0 + ; CHECK: [[COPY:%[0-9]+]]:_(p0) = COPY $x0 + ; CHECK: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 28 + ; CHECK: [[PTR_ADD:%[0-9]+]]:_(p0) = G_PTR_ADD [[COPY]], [[C]](s64) + ; CHECK: $x0 = COPY [[PTR_ADD]](p0) + ; CHECK: RET_ReallyLR implicit $x0 + %0:_(p0) = COPY $x0 + %1:_(s64) = G_CONSTANT i64 4 + %2:_(s64) = G_CONSTANT i64 12 + %6:_(s32) = G_TRUNC %2(s64) + %7:_(s64) = G_SEXT %6(s32) + %3:_(p0) = G_PTR_ADD %0(p0), %1 + %4:_(p0) = G_PTR_ADD %3(p0), %2 + %5:_(p0) = G_PTR_ADD %4(p0), %7 + $x0 = COPY %5(p0) + RET_ReallyLR implicit $x0 +...