Index: llvm/include/llvm/IR/Intrinsics.td =================================================================== --- llvm/include/llvm/IR/Intrinsics.td +++ llvm/include/llvm/IR/Intrinsics.td @@ -1182,11 +1182,11 @@ ImmArg>]>; def int_experimental_gc_result : Intrinsic<[llvm_any_ty], [llvm_token_ty], - [IntrReadMem]>; + [IntrNoMem]>; def int_experimental_gc_relocate : Intrinsic<[llvm_any_ty], [llvm_token_ty, llvm_i32_ty, llvm_i32_ty], - [IntrReadMem, ImmArg>, + [IntrNoMem, ImmArg>, ImmArg>]>; //===------------------------ Coroutine Intrinsics ---------------===// Index: llvm/lib/Transforms/Scalar/EarlyCSE.cpp =================================================================== --- llvm/lib/Transforms/Scalar/EarlyCSE.cpp +++ llvm/lib/Transforms/Scalar/EarlyCSE.cpp @@ -280,6 +280,13 @@ return hash_combine(II->getOpcode(), LHS, RHS); } + // gc.relocate is 'special' call: its second and third operands are + // not real values, but indices into statepoint's argument list. + // Get values they point to. + if (const GCRelocateInst *GCR = dyn_cast(Inst)) + return hash_combine(GCR->getOpcode(), GCR->getOperand(0), + GCR->getBasePtr(), GCR->getDerivedPtr()); + // Mix in the opcode. return hash_combine( Inst->getOpcode(), @@ -341,6 +348,13 @@ LII->getArgOperand(1) == RII->getArgOperand(0); } + // See comment above in `getHashValue()`. + if (const GCRelocateInst *GCR1 = dyn_cast(LHSI)) + if (const GCRelocateInst *GCR2 = dyn_cast(RHSI)) + return GCR1->getOperand(0) == GCR2->getOperand(0) && + GCR1->getBasePtr() == GCR2->getBasePtr() && + GCR1->getDerivedPtr() == GCR2->getDerivedPtr(); + // Min/max can occur with commuted operands, non-canonical predicates, // and/or non-canonical operands. // Selects can be non-trivially equivalent via inverted conditions and swaps. @@ -454,13 +468,6 @@ unsigned DenseMapInfo::getHashValue(CallValue Val) { Instruction *Inst = Val.Inst; - // gc.relocate is 'special' call: its second and third operands are - // not real values, but indices into statepoint's argument list. - // Get values they point to. - if (const GCRelocateInst *GCR = dyn_cast(Inst)) - return hash_combine(GCR->getOpcode(), GCR->getOperand(0), - GCR->getBasePtr(), GCR->getDerivedPtr()); - // Hash all of the operands as pointers and mix in the opcode. return hash_combine( Inst->getOpcode(), @@ -472,13 +479,6 @@ if (LHS.isSentinel() || RHS.isSentinel()) return LHSI == RHSI; - // See comment above in `getHashValue()`. - if (const GCRelocateInst *GCR1 = dyn_cast(LHSI)) - if (const GCRelocateInst *GCR2 = dyn_cast(RHSI)) - return GCR1->getOperand(0) == GCR2->getOperand(0) && - GCR1->getBasePtr() == GCR2->getBasePtr() && - GCR1->getDerivedPtr() == GCR2->getDerivedPtr(); - return LHSI->isIdenticalTo(RHSI); } Index: llvm/lib/Transforms/Scalar/GVN.cpp =================================================================== --- llvm/lib/Transforms/Scalar/GVN.cpp +++ llvm/lib/Transforms/Scalar/GVN.cpp @@ -62,6 +62,7 @@ #include "llvm/IR/Operator.h" #include "llvm/IR/PassManager.h" #include "llvm/IR/PatternMatch.h" +#include "llvm/IR/Statepoint.h" #include "llvm/IR/Type.h" #include "llvm/IR/Use.h" #include "llvm/IR/Value.h" @@ -289,8 +290,17 @@ Expression e; e.type = I->getType(); e.opcode = I->getOpcode(); - for (Use &Op : I->operands()) - e.varargs.push_back(lookupOrAdd(Op)); + if (const GCRelocateInst *GCR = dyn_cast(I)) { + // gc.relocate is 'special' call: its second and third operands are + // not real values, but indices into statepoint's argument list. + // Use the refered to values for purposes of identity. + e.varargs.push_back(lookupOrAdd(GCR->getOperand(0))); + e.varargs.push_back(lookupOrAdd(GCR->getBasePtr())); + e.varargs.push_back(lookupOrAdd(GCR->getDerivedPtr())); + } else { + for (Use &Op : I->operands()) + e.varargs.push_back(lookupOrAdd(Op)); + } if (I->isCommutative()) { // Ensure that commutative instructions that only differ by a permutation // of their operands get the same value number by sorting the operand value Index: llvm/test/Transforms/GVN/gc_relocate.ll =================================================================== --- llvm/test/Transforms/GVN/gc_relocate.ll +++ llvm/test/Transforms/GVN/gc_relocate.ll @@ -28,14 +28,10 @@ ; CHECK-NEXT: entry: ; CHECK-NEXT: [[SAFEPOINT_TOKEN:%.*]] = call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @func, i32 0, i32 0, i32 0, i32 0) [ "gc-live"(i32 addrspace(1)* [[IN:%.*]], i32 addrspace(1)* [[IN]]) ] ; CHECK-NEXT: [[BASE:%.*]] = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token [[SAFEPOINT_TOKEN]], i32 0, i32 0) -; CHECK-NEXT: [[DERIVED:%.*]] = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token [[SAFEPOINT_TOKEN]], i32 0, i32 1) -; CHECK-NEXT: [[SAFEPOINT_TOKEN2:%.*]] = call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @func, i32 0, i32 0, i32 0, i32 0) [ "gc-live"(i32 addrspace(1)* [[BASE]], i32 addrspace(1)* [[DERIVED]]) ] +; CHECK-NEXT: [[SAFEPOINT_TOKEN2:%.*]] = call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @func, i32 0, i32 0, i32 0, i32 0) [ "gc-live"(i32 addrspace(1)* [[BASE]], i32 addrspace(1)* [[BASE]]) ] ; CHECK-NEXT: [[BASE_RELOC:%.*]] = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token [[SAFEPOINT_TOKEN2]], i32 0, i32 0) -; CHECK-NEXT: [[DERIVED_RELOC:%.*]] = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token [[SAFEPOINT_TOKEN2]], i32 0, i32 1) ; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 addrspace(1)* [[BASE_RELOC]], null -; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i32 addrspace(1)* [[DERIVED_RELOC]], null -; CHECK-NEXT: [[CMP:%.*]] = and i1 [[CMP1]], [[CMP2]] -; CHECK-NEXT: ret i1 [[CMP]] +; CHECK-NEXT: ret i1 [[CMP1]] ; entry: %safepoint_token = call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @func, i32 0, i32 0, i32 0, i32 0) ["gc-live"(i32 addrspace(1)* %in, i32 addrspace(1)* %in)]