InstCombine: Fix a crash in PointerReplacer when constructing a new PHI (#130256)

When constructing a PHI node in `PointerReplacer::replace`, the incoming
operands are expected to have already been replaced and in the
replacement map. However, when one of the incoming operands is a load,
the search of the map is unsuccessful, and a nullptr is returned from
`getReplacement`. The reason is that, when a load is replaced, all the
uses of the load has been actually replaced by the new load. It is
useless to insert the original load into the map. Instead, we should
place the new load into the map to meet the expectation of the later map
search.

Fixes: SWDEV-516420
This commit is contained in:
Changpeng Fang 2025-03-09 20:21:36 -07:00 committed by GitHub
parent 64c73d5c71
commit fa45bf4300
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 46 additions and 1 deletions

View File

@ -360,7 +360,10 @@ void PointerReplacer::replace(Instruction *I) {
IC.InsertNewInstWith(NewI, LT->getIterator());
IC.replaceInstUsesWith(*LT, NewI);
WorkMap[LT] = NewI;
// LT has actually been replaced by NewI. It is useless to insert LT into
// the map. Instead, we insert NewI into the map to indicate this is the
// replacement (new value).
WorkMap[NewI] = NewI;
} else if (auto *PHI = dyn_cast<PHINode>(I)) {
Type *NewTy = getReplacement(PHI->getIncomingValue(0))->getType();
auto *NewPHI = PHINode::Create(NewTy, PHI->getNumIncomingValues(),

View File

@ -0,0 +1,42 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
; RUN: opt -passes=instcombine -S -o - %s | FileCheck %s
target triple = "amdgcn-amd-amdhsa"
%double_double = type { double, double }
declare void @llvm.memcpy.p0.p0.i64(ptr, ptr, i64, i1)
define void @_test(ptr addrspace(4) byref(%double_double) align 8 %in) {
; CHECK-LABEL: define void @_test(
; CHECK-SAME: ptr addrspace(4) byref([[DOUBLE_DOUBLE:%.*]]) align 8 [[IN:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: [[ALPHA_UNION:%.*]] = addrspacecast ptr addrspace(4) [[IN]] to ptr
; CHECK-NEXT: [[LOAD:%.*]] = load i8, ptr addrspace(5) null, align 1
; CHECK-NEXT: [[LOADEDV:%.*]] = trunc i8 [[LOAD]] to i1
; CHECK-NEXT: br i1 [[LOADEDV]], label %[[COND_END:.*]], label %[[COND_FALSE:.*]]
; CHECK: [[COND_FALSE]]:
; CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr addrspace(4) [[IN]], align 8
; CHECK-NEXT: br label %[[COND_END]]
; CHECK: [[COND_END]]:
; CHECK-NEXT: [[COND1:%.*]] = phi ptr [ [[TMP0]], %[[COND_FALSE]] ], [ [[ALPHA_UNION]], %[[ENTRY]] ]
; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 1 dereferenceable(16) poison, ptr noundef nonnull align 1 dereferenceable(16) [[COND1]], i64 16, i1 false)
; CHECK-NEXT: ret void
;
entry:
%coerce = alloca %double_double, align 8, addrspace(5)
%alpha_union = addrspacecast ptr addrspace(5) %coerce to ptr
call void @llvm.memcpy.p5.p4.i64(ptr addrspace(5) align 8 %coerce, ptr addrspace(4) align 8 %in, i64 16, i1 false)
%load1 = load i8, ptr addrspace(5) null, align 1
%loadedv = trunc i8 %load1 to i1
br i1 %loadedv, label %cond.end, label %cond.false
cond.false:
%load2 = load ptr, ptr addrspace(5) %coerce, align 8
br label %cond.end
cond.end:
%cond = phi ptr [ %load2, %cond.false ], [ %alpha_union, %entry ]
call void @llvm.memcpy.p0.p0.i64(ptr poison, ptr %cond, i64 16, i1 false)
ret void
}