Index: llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h =================================================================== --- llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h +++ llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h @@ -288,6 +288,10 @@ bool applyCombineAddP2IToPtrAdd(MachineInstr &MI, std::pair &PtrRegAndCommute); + // Transform G_PTR_ADD (G_PTRTOINT C1), C2 -> C1 + C2 + bool matchCombineConstPtrAddToI2P(MachineInstr &MI, int64_t &NewCst); + bool applyCombineConstPtrAddToI2P(MachineInstr &MI, int64_t &NewCst); + /// Transform anyext(trunc(x)) to x. bool matchCombineAnyExtTrunc(MachineInstr &MI, Register &Reg); bool applyCombineAnyExtTrunc(MachineInstr &MI, Register &Reg); Index: llvm/include/llvm/Target/GlobalISel/Combine.td =================================================================== --- llvm/include/llvm/Target/GlobalISel/Combine.td +++ llvm/include/llvm/Target/GlobalISel/Combine.td @@ -339,6 +339,14 @@ (apply [{ return Helper.applyCombineAddP2IToPtrAdd(*${root}, ${info}); }]) >; +// Fold (ptr_add (int2ptr C1), C2) -> C1 + C2 +def const_ptradd_to_i2p_matchinfo : GIDefMatchData<"int64_t">; +def const_ptradd_to_i2p: GICombineRule< + (defs root:$root, const_ptradd_to_i2p_matchinfo:$info), + (match (wip_match_opcode G_PTR_ADD):$root, + [{ return Helper.matchCombineConstPtrAddToI2P(*${root}, ${info}); }]), + (apply [{ return Helper.applyCombineConstPtrAddToI2P(*${root}, ${info}); }]) +>; // Simplify: (logic_op (op x...), (op y...)) -> (op (logic_op x, y)) def hoist_logic_op_with_same_opcode_hands: GICombineRule < @@ -505,6 +513,8 @@ i2p_to_p2i, anyext_trunc_fold, fneg_fneg_fold, right_identity_one]>; +def const_combines : GICombineGroup<[constant_fp_op, const_ptradd_to_i2p]>; + def known_bits_simplifications : GICombineGroup<[ and_trivial_mask, redundant_sext_inreg]>; @@ -525,4 +535,4 @@ not_cmp_fold, opt_brcond_by_inverting_cond, unmerge_merge, fabs_fabs_fold, unmerge_cst, unmerge_dead_to_trunc, unmerge_zext_to_zext, trunc_ext_fold, trunc_shl, - constant_fp_op, xor_of_and_with_same_reg]>; + xor_of_and_with_same_reg, const_combines]>; Index: llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp =================================================================== --- llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp +++ llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp @@ -1999,6 +1999,35 @@ return true; } +bool CombinerHelper::matchCombineConstPtrAddToI2P(MachineInstr &MI, + int64_t &NewCst) { + assert(MI.getOpcode() == TargetOpcode::G_PTR_ADD && "Expected a G_PTR_ADD"); + Register LHS = MI.getOperand(1).getReg(); + Register RHS = MI.getOperand(2).getReg(); + MachineRegisterInfo &MRI = Builder.getMF().getRegInfo(); + + if (auto RHSCst = getConstantVRegVal(RHS, MRI)) { + int64_t Cst; + if (mi_match(LHS, MRI, m_GIntToPtr(m_ICst(Cst)))) { + NewCst = Cst + *RHSCst; + return true; + } + } + + return false; +} + +bool CombinerHelper::applyCombineConstPtrAddToI2P(MachineInstr &MI, + int64_t &NewCst) { + assert(MI.getOpcode() == TargetOpcode::G_PTR_ADD && "Expected a G_PTR_ADD"); + Register Dst = MI.getOperand(0).getReg(); + + Builder.setInstrAndDebugLoc(MI); + Builder.buildConstant(Dst, NewCst); + MI.eraseFromParent(); + return true; +} + bool CombinerHelper::matchCombineAnyExtTrunc(MachineInstr &MI, Register &Reg) { assert(MI.getOpcode() == TargetOpcode::G_ANYEXT && "Expected a G_ANYEXT"); Register DstReg = MI.getOperand(0).getReg(); Index: llvm/test/CodeGen/AArch64/GlobalISel/combine-ptradd-int2ptr.mir =================================================================== --- /dev/null +++ llvm/test/CodeGen/AArch64/GlobalISel/combine-ptradd-int2ptr.mir @@ -0,0 +1,52 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py +# RUN: llc -run-pass=aarch64-prelegalizer-combiner -verify-machineinstrs -mtriple aarch64-unknown-unknown %s -o - | FileCheck %s +# RUN: llc -debugify-and-strip-all-safe -run-pass=aarch64-prelegalizer-combiner -verify-machineinstrs -mtriple aarch64-unknown-unknown %s -o - | FileCheck %s + +--- +name: agc.test_combine_ptradd_constants_intres +body: | + bb.1: + liveins: $x0 + ; CHECK-LABEL: name: agc.test_combine_ptradd_constants_intres + ; CHECK: [[C:%[0-9]+]]:_(p64) = G_CONSTANT i64 44 + ; CHECK: [[PTRTOINT:%[0-9]+]]:_(s64) = G_PTRTOINT [[C]](p64) + ; CHECK: $x0 = COPY [[PTRTOINT]](s64) + %1:_(s32) = G_CONSTANT i32 42 + %2:_(s32) = G_CONSTANT i32 2 + %3:_(p64) = G_INTTOPTR %2 + %4:_(p64) = G_PTR_ADD %3, %1 + %5:_(s64) = G_PTRTOINT %4 + $x0 = COPY %5(s64) +... +--- +name: agc.test_combine_ptradd_constants_ptrres +body: | + bb.1: + liveins: $x0 + ; CHECK-LABEL: name: agc.test_combine_ptradd_constants_ptrres + ; CHECK: [[C:%[0-9]+]]:_(p64) = G_CONSTANT i64 44 + ; CHECK: $x0 = COPY [[C]](p64) + %1:_(s32) = G_CONSTANT i32 42 + %2:_(s32) = G_CONSTANT i32 2 + %3:_(p64) = G_INTTOPTR %2 + %4:_(p64) = G_PTR_ADD %3, %1 + $x0 = COPY %4(p64) +... +--- +name: agc.test_not_combine_variable_ptradd +body: | + bb.1: + liveins: $x0, $x1 + ; Ensure non-constant G_PTR_ADDs are not folded. + ; CHECK-LABEL: name: agc.test_not_combine_variable_ptradd + ; CHECK: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 42 + ; CHECK: [[COPY:%[0-9]+]]:_(p64) = COPY $x1 + ; CHECK: [[PTR_ADD:%[0-9]+]]:_(p64) = G_PTR_ADD [[COPY]], [[C]](s32) + ; CHECK: [[PTRTOINT:%[0-9]+]]:_(s64) = G_PTRTOINT [[PTR_ADD]](p64) + ; CHECK: $x0 = COPY [[PTRTOINT]](s64) + %1:_(s32) = G_CONSTANT i32 42 + %2:_(p64) = COPY $x1 + %3:_(p64) = G_PTR_ADD %2, %1 + %4:_(s64) = G_PTRTOINT %3 + $x0 = COPY %4(s64) +...