diff --git a/llvm/lib/Transforms/Scalar/LICM.cpp b/llvm/lib/Transforms/Scalar/LICM.cpp index 91ef2b4b7c183..f360379e9df04 100644 --- a/llvm/lib/Transforms/Scalar/LICM.cpp +++ b/llvm/lib/Transforms/Scalar/LICM.cpp @@ -65,11 +65,12 @@ #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Dominators.h" +#include "llvm/IR/IRBuilder.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/IntrinsicInst.h" -#include "llvm/IR/IRBuilder.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Metadata.h" +#include "llvm/IR/Module.h" #include "llvm/IR/PatternMatch.h" #include "llvm/IR/PredIteratorCache.h" #include "llvm/InitializePasses.h" @@ -1328,6 +1329,20 @@ bool llvm::canSinkOrHoistInst(Instruction &I, AAResults *AA, DominatorTree *DT, } } return true; + } else if (auto *PTII = dyn_cast(&I)) { + const DataLayout &DL = I.getModule()->getDataLayout(); + // Non-integral pointers may not have a stable bit representation, therefore + // casting them to an integer is not loop invariant. + if (DL.isNonIntegralPointerType(PTII->getPointerOperand()->getType())) { + return false; + } + } else if (auto *ITPI = dyn_cast(&I)) { + const DataLayout &DL = I.getModule()->getDataLayout(); + // Non-integral pointers may not have a stable bit representation, therefore + // casting an integer to a non-integral pointer type is not loop invariant. + if (DL.isNonIntegralPointerType(ITPI->getType())) { + return false; + } } assert(!I.mayReadOrWriteMemory() && "unhandled aliasing"); diff --git a/llvm/test/Transforms/LICM/non-integral-pointers.ll b/llvm/test/Transforms/LICM/non-integral-pointers.ll new file mode 100644 index 0000000000000..683bb03005476 --- /dev/null +++ b/llvm/test/Transforms/LICM/non-integral-pointers.ll @@ -0,0 +1,96 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 +; RUN: opt -passes=licm -S < %s | FileCheck %s + +target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-ni:1" + +declare void @use_i64(i64 %0) +declare void @use_p1(ptr addrspace(1) %0) +declare i1 @cond() + +define void @dont_hoist_ptrtoint(ptr addrspace(1) %p) { +; CHECK-LABEL: define void @dont_hoist_ptrtoint( +; CHECK-SAME: ptr addrspace(1) [[P:%.*]]) { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: br label %[[LOOP:.*]] +; CHECK: [[LOOP]]: +; CHECK-NEXT: [[P_INT:%.*]] = ptrtoint ptr addrspace(1) [[P]] to i64 +; CHECK-NEXT: call void @use_i64(i64 [[P_INT]]) +; CHECK-NEXT: br label %[[LOOP]] +; +entry: + br label %loop + +loop: + %p.int = ptrtoint ptr addrspace(1) %p to i64 + call void @use_i64(i64 %p.int) + br label %loop +} + +define void @dont_hoist_inttoptr(i64 %p.int) { +; CHECK-LABEL: define void @dont_hoist_inttoptr( +; CHECK-SAME: i64 [[P_INT:%.*]]) { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: br label %[[LOOP:.*]] +; CHECK: [[LOOP]]: +; CHECK-NEXT: [[P:%.*]] = inttoptr i64 [[P_INT]] to ptr addrspace(1) +; CHECK-NEXT: call void @use_p1(ptr addrspace(1) [[P]]) +; CHECK-NEXT: br label %[[LOOP]] +; +entry: + br label %loop + +loop: + %p = inttoptr i64 %p.int to ptr addrspace(1) + call void @use_p1(ptr addrspace(1) %p) + br label %loop +} + +define i64 @dont_sink_ptrtoint(ptr addrspace(1) %p) { +; CHECK-LABEL: define i64 @dont_sink_ptrtoint( +; CHECK-SAME: ptr addrspace(1) [[P:%.*]]) { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: br label %[[LOOP:.*]] +; CHECK: [[LOOP]]: +; CHECK-NEXT: [[P_INT_LE:%.*]] = ptrtoint ptr addrspace(1) [[P]] to i64 +; CHECK-NEXT: [[C:%.*]] = call i1 @cond() +; CHECK-NEXT: br i1 [[C]], label %[[LOOP]], label %[[EXIT:.*]] +; CHECK: [[EXIT]]: +; CHECK-NEXT: [[P_INT_LCSSA:%.*]] = phi i64 [ [[P_INT_LE]], %[[LOOP]] ] +; CHECK-NEXT: ret i64 [[P_INT_LCSSA]] +; +entry: + br label %loop + +loop: + %p.int = ptrtoint ptr addrspace(1) %p to i64 + %c = call i1 @cond() + br i1 %c, label %loop, label %exit + +exit: + ret i64 %p.int +} + +define ptr addrspace(1) @dont_sink_inttoptr(i64 %p.int) { +; CHECK-LABEL: define ptr addrspace(1) @dont_sink_inttoptr( +; CHECK-SAME: i64 [[P_INT:%.*]]) { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: br label %[[LOOP:.*]] +; CHECK: [[LOOP]]: +; CHECK-NEXT: [[P_LE:%.*]] = inttoptr i64 [[P_INT]] to ptr addrspace(1) +; CHECK-NEXT: [[C:%.*]] = call i1 @cond() +; CHECK-NEXT: br i1 [[C]], label %[[LOOP]], label %[[EXIT:.*]] +; CHECK: [[EXIT]]: +; CHECK-NEXT: [[P_LCSSA:%.*]] = phi ptr addrspace(1) [ [[P_LE]], %[[LOOP]] ] +; CHECK-NEXT: ret ptr addrspace(1) [[P_LCSSA]] +; +entry: + br label %loop + +loop: + %p = inttoptr i64 %p.int to ptr addrspace(1) + %c = call i1 @cond() + br i1 %c, label %loop, label %exit + +exit: + ret ptr addrspace(1) %p +}