From 0a9ae5c3a5e8ce240d1474d14c2b9208782148c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Csan=C3=A1d=20Hajd=C3=BA?= Date: Thu, 20 Jun 2024 11:45:06 +0200 Subject: [PATCH 1/3] [LICM] Prevent LICM of ptrtoint and inttoptr when using non-integral pointers Non-integral pointers don't have a stable bit representation, i.e. subsequent executions of `ptrtoint` or `inttoptr` instructions can create different results, therefore it is invalid to move these instructions outside of a loop when they use non-integral pointer types. --- llvm/lib/Transforms/Scalar/LICM.cpp | 15 +++++ .../Transforms/LICM/non-integral-pointers.ll | 67 +++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 llvm/test/Transforms/LICM/non-integral-pointers.ll diff --git a/llvm/lib/Transforms/Scalar/LICM.cpp b/llvm/lib/Transforms/Scalar/LICM.cpp index 91ef2b4b7c183..f286d910f932e 100644 --- a/llvm/lib/Transforms/Scalar/LICM.cpp +++ b/llvm/lib/Transforms/Scalar/LICM.cpp @@ -70,6 +70,7 @@ #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..01336d7d812b3 --- /dev/null +++ b/llvm/test/Transforms/LICM/non-integral-pointers.ll @@ -0,0 +1,67 @@ +; 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: @dont_hoist_ptrtoint +; CHECK-LABEL: loop +; CHECK: ptrtoint +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: @dont_hoist_inttoptr +; CHECK-LABEL: loop +; CHECK: inttoptr +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: @dont_sink_ptrtoint +; CHECK-LABEL: loop +; CHECK: ptrtoint +; CHECK-LABEL: exit +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: @dont_sink_inttoptr +; CHECK-LABEL: loop +; CHECK: inttoptr +; CHECK-LABEL: exit +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 +} From ffa6cd4efdd7a5286dacaf79afeb89eb359c7dd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Csan=C3=A1d=20Hajd=C3=BA?= Date: Fri, 12 Jul 2024 10:39:37 +0200 Subject: [PATCH 2/3] Rerun clang-format --- llvm/lib/Transforms/Scalar/LICM.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/lib/Transforms/Scalar/LICM.cpp b/llvm/lib/Transforms/Scalar/LICM.cpp index f286d910f932e..f360379e9df04 100644 --- a/llvm/lib/Transforms/Scalar/LICM.cpp +++ b/llvm/lib/Transforms/Scalar/LICM.cpp @@ -65,9 +65,9 @@ #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" From fac818f70903e73cdf29ab5628087554d990a3d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Csan=C3=A1d=20Hajd=C3=BA?= Date: Fri, 12 Jul 2024 11:09:55 +0200 Subject: [PATCH 3/3] Run update_test_checks.py on the test file --- .../Transforms/LICM/non-integral-pointers.ll | 57 ++++++++++++++----- 1 file changed, 43 insertions(+), 14 deletions(-) diff --git a/llvm/test/Transforms/LICM/non-integral-pointers.ll b/llvm/test/Transforms/LICM/non-integral-pointers.ll index 01336d7d812b3..683bb03005476 100644 --- a/llvm/test/Transforms/LICM/non-integral-pointers.ll +++ b/llvm/test/Transforms/LICM/non-integral-pointers.ll @@ -1,3 +1,4 @@ +; 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" @@ -7,9 +8,15 @@ declare void @use_p1(ptr addrspace(1) %0) declare i1 @cond() define void @dont_hoist_ptrtoint(ptr addrspace(1) %p) { -; CHECK-LABEL: @dont_hoist_ptrtoint -; CHECK-LABEL: loop -; CHECK: ptrtoint +; 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 @@ -20,9 +27,15 @@ loop: } define void @dont_hoist_inttoptr(i64 %p.int) { -; CHECK-LABEL: @dont_hoist_inttoptr -; CHECK-LABEL: loop -; CHECK: inttoptr +; 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 @@ -33,10 +46,18 @@ loop: } define i64 @dont_sink_ptrtoint(ptr addrspace(1) %p) { -; CHECK-LABEL: @dont_sink_ptrtoint -; CHECK-LABEL: loop -; CHECK: ptrtoint -; CHECK-LABEL: exit +; 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 @@ -50,10 +71,18 @@ exit: } define ptr addrspace(1) @dont_sink_inttoptr(i64 %p.int) { -; CHECK-LABEL: @dont_sink_inttoptr -; CHECK-LABEL: loop -; CHECK: inttoptr -; CHECK-LABEL: exit +; 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