[GlobalISel] Fix incorrect sign extension when combining G_INTTOPTR and G_PTR_ADD

The GlobalISel combiner currently uses sign extension when manipulating
the LHS constant when combining a sequence of the following sequence of
machine instructions into a single constant:
```
  %0:_(s32) = G_CONSTANT i32 <CONSTANT>
  %1:_(p0) = G_INTTOPTR %0:_(s32)
  %2:_(s64) = G_CONSTANT i64 <CONSTANT>
  %3:_(p0) = G_PTR_ADD %1:_, %2:_(s64)
```

This causes an issue when the bit width of the first contant and the
target pointer size are different, as G_INTTOPTR has no sign extension
semantics.

This patch fixes this by capture an arbitrary precision in when matching
the constant, allowing the matching function to correctly zero extend
it.

Reviewed By: arsenm

Differential Revision: https://reviews.llvm.org/D116941
This commit is contained in:
Lucas Prates 2022-01-10 10:19:27 +00:00
parent fabf1de132
commit 283f5a198a
6 changed files with 67 additions and 13 deletions

View File

@ -353,8 +353,8 @@ public:
std::pair<Register, bool> &PtrRegAndCommute); std::pair<Register, bool> &PtrRegAndCommute);
// Transform G_PTR_ADD (G_PTRTOINT C1), C2 -> C1 + C2 // Transform G_PTR_ADD (G_PTRTOINT C1), C2 -> C1 + C2
bool matchCombineConstPtrAddToI2P(MachineInstr &MI, int64_t &NewCst); bool matchCombineConstPtrAddToI2P(MachineInstr &MI, APInt &NewCst);
void applyCombineConstPtrAddToI2P(MachineInstr &MI, int64_t &NewCst); void applyCombineConstPtrAddToI2P(MachineInstr &MI, APInt &NewCst);
/// Transform anyext(trunc(x)) to x. /// Transform anyext(trunc(x)) to x.
bool matchCombineAnyExtTrunc(MachineInstr &MI, Register &Reg); bool matchCombineAnyExtTrunc(MachineInstr &MI, Register &Reg);

View File

@ -13,6 +13,7 @@
#ifndef LLVM_CODEGEN_GLOBALISEL_MIPATTERNMATCH_H #ifndef LLVM_CODEGEN_GLOBALISEL_MIPATTERNMATCH_H
#define LLVM_CODEGEN_GLOBALISEL_MIPATTERNMATCH_H #define LLVM_CODEGEN_GLOBALISEL_MIPATTERNMATCH_H
#include "llvm/ADT/APInt.h"
#include "llvm/CodeGen/GlobalISel/Utils.h" #include "llvm/CodeGen/GlobalISel/Utils.h"
#include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/IR/InstrTypes.h" #include "llvm/IR/InstrTypes.h"
@ -59,11 +60,26 @@ inline OneNonDBGUse_match<SubPat> m_OneNonDBGUse(const SubPat &SP) {
return SP; return SP;
} }
struct ConstantMatch { template <typename ConstT>
int64_t &CR; inline Optional<ConstT> matchConstant(Register, const MachineRegisterInfo &);
ConstantMatch(int64_t &C) : CR(C) {}
template <>
inline Optional<APInt> matchConstant(Register Reg,
const MachineRegisterInfo &MRI) {
return getIConstantVRegVal(Reg, MRI);
}
template <>
inline Optional<int64_t> matchConstant(Register Reg,
const MachineRegisterInfo &MRI) {
return getIConstantVRegSExtVal(Reg, MRI);
}
template <typename ConstT> struct ConstantMatch {
ConstT &CR;
ConstantMatch(ConstT &C) : CR(C) {}
bool match(const MachineRegisterInfo &MRI, Register Reg) { bool match(const MachineRegisterInfo &MRI, Register Reg) {
if (auto MaybeCst = getIConstantVRegSExtVal(Reg, MRI)) { if (auto MaybeCst = matchConstant<ConstT>(Reg, MRI)) {
CR = *MaybeCst; CR = *MaybeCst;
return true; return true;
} }
@ -71,7 +87,12 @@ struct ConstantMatch {
} }
}; };
inline ConstantMatch m_ICst(int64_t &Cst) { return ConstantMatch(Cst); } inline ConstantMatch<APInt> m_ICst(APInt &Cst) {
return ConstantMatch<APInt>(Cst);
}
inline ConstantMatch<int64_t> m_ICst(int64_t &Cst) {
return ConstantMatch<int64_t>(Cst);
}
struct GCstAndRegMatch { struct GCstAndRegMatch {
Optional<ValueAndVReg> &ValReg; Optional<ValueAndVReg> &ValReg;

View File

@ -391,7 +391,7 @@ def add_p2i_to_ptradd : GICombineRule<
>; >;
// Fold (ptr_add (int2ptr C1), C2) -> C1 + C2 // Fold (ptr_add (int2ptr C1), C2) -> C1 + C2
def const_ptradd_to_i2p_matchinfo : GIDefMatchData<"int64_t">; def const_ptradd_to_i2p_matchinfo : GIDefMatchData<"APInt">;
def const_ptradd_to_i2p: GICombineRule< def const_ptradd_to_i2p: GICombineRule<
(defs root:$root, const_ptradd_to_i2p_matchinfo:$info), (defs root:$root, const_ptradd_to_i2p_matchinfo:$info),
(match (wip_match_opcode G_PTR_ADD):$root, (match (wip_match_opcode G_PTR_ADD):$root,

View File

@ -2025,16 +2025,19 @@ void CombinerHelper::applyCombineAddP2IToPtrAdd(
} }
bool CombinerHelper::matchCombineConstPtrAddToI2P(MachineInstr &MI, bool CombinerHelper::matchCombineConstPtrAddToI2P(MachineInstr &MI,
int64_t &NewCst) { APInt &NewCst) {
auto &PtrAdd = cast<GPtrAdd>(MI); auto &PtrAdd = cast<GPtrAdd>(MI);
Register LHS = PtrAdd.getBaseReg(); Register LHS = PtrAdd.getBaseReg();
Register RHS = PtrAdd.getOffsetReg(); Register RHS = PtrAdd.getOffsetReg();
MachineRegisterInfo &MRI = Builder.getMF().getRegInfo(); MachineRegisterInfo &MRI = Builder.getMF().getRegInfo();
if (auto RHSCst = getIConstantVRegSExtVal(RHS, MRI)) { if (auto RHSCst = getIConstantVRegVal(RHS, MRI)) {
int64_t Cst; APInt Cst;
if (mi_match(LHS, MRI, m_GIntToPtr(m_ICst(Cst)))) { if (mi_match(LHS, MRI, m_GIntToPtr(m_ICst(Cst)))) {
NewCst = Cst + *RHSCst; auto DstTy = MRI.getType(PtrAdd.getReg(0));
// G_INTTOPTR uses zero-extension
NewCst = Cst.zextOrTrunc(DstTy.getSizeInBits());
NewCst += RHSCst->sextOrTrunc(DstTy.getSizeInBits());
return true; return true;
} }
} }
@ -2043,7 +2046,7 @@ bool CombinerHelper::matchCombineConstPtrAddToI2P(MachineInstr &MI,
} }
void CombinerHelper::applyCombineConstPtrAddToI2P(MachineInstr &MI, void CombinerHelper::applyCombineConstPtrAddToI2P(MachineInstr &MI,
int64_t &NewCst) { APInt &NewCst) {
auto &PtrAdd = cast<GPtrAdd>(MI); auto &PtrAdd = cast<GPtrAdd>(MI);
Register Dst = PtrAdd.getReg(0); Register Dst = PtrAdd.getReg(0);

View File

@ -50,3 +50,18 @@ body: |
%4:_(s64) = G_PTRTOINT %3 %4:_(s64) = G_PTRTOINT %3
$x0 = COPY %4(s64) $x0 = COPY %4(s64)
... ...
---
name: test_combine_zero_extend
body: |
bb.1:
liveins: $x0
; CHECK-LABEL: name: test_combine_zero_extend
; CHECK: [[C:%[0-9]+]]:_(p0) = G_CONSTANT i64 4291891236
; CHECK-NEXT: $x0 = COPY [[C]](p0)
%0:_(s32) = G_CONSTANT i32 -3076096
%1:_(p0) = G_INTTOPTR %0:_(s32)
%2:_(s64) = G_CONSTANT i64 36
%3:_(p0) = G_PTR_ADD %1:_, %2:_(s64)
$x0 = COPY %3
...

View File

@ -0,0 +1,15 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc -mtriple=aarch64-none-eabi -global-isel -verify-machineinstrs %s -o - | FileCheck %s
define dso_local void @fn() {
; CHECK-LABEL: fn:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: mov x8, #4132
; CHECK-NEXT: mov w9, #1
; CHECK-NEXT: movk x8, #65489, lsl #16
; CHECK-NEXT: str w9, [x8]
; CHECK-NEXT: ret
entry:
store i32 1, i32* bitcast (i8* getelementptr inbounds (i8, i8* inttoptr (i32 -3076096 to i8*), i64 36) to i32*), align 4
ret void
}