Skip to content

Commit 1d8f2e5

Browse files
committed
[SCEVExpander] Support expanding nonintegral pointers with constant base.
Currently SCEVExpander creates inttoptr for non-integral pointers if the base is a null constant for example. This results in invalid IR. This patch changes InsertNoopCastOfTo to emit a GEP & bitcast to convert to a non-integral pointer. First, a GEP of i8* null is generated and the integral value is used as index. The GEP is then bitcasted to the target type. This was exposed by D71539. Reviewed By: efriedma Differential Revision: https://reviews.llvm.org/D87827
1 parent d716f16 commit 1d8f2e5

File tree

2 files changed

+66
-0
lines changed

2 files changed

+66
-0
lines changed

llvm/lib/Transforms/Utils/ScalarEvolutionExpander.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,20 @@ Value *SCEVExpander::InsertNoopCastOfTo(Value *V, Type *Ty) {
126126
assert(SE.getTypeSizeInBits(V->getType()) == SE.getTypeSizeInBits(Ty) &&
127127
"InsertNoopCastOfTo cannot change sizes!");
128128

129+
auto *PtrTy = dyn_cast<PointerType>(Ty);
130+
// inttoptr only works for integral pointers. For non-integral pointers, we
131+
// can create a GEP on i8* null with the integral value as index. Note that
132+
// it is safe to use GEP of null instead of inttoptr here, because only
133+
// expressions already based on a GEP of null should be converted to pointers
134+
// during expansion.
135+
if (Op == Instruction::IntToPtr && DL.isNonIntegralPointerType(PtrTy)) {
136+
auto *Int8PtrTy = Builder.getInt8PtrTy(PtrTy->getAddressSpace());
137+
assert(DL.getTypeAllocSize(Int8PtrTy->getElementType()) == 1 &&
138+
"alloc size of i8 must by 1 byte for the GEP to be correct");
139+
auto *GEP = Builder.CreateGEP(
140+
Builder.getInt8Ty(), Constant::getNullValue(Int8PtrTy), V, "uglygep");
141+
return Builder.CreateBitCast(GEP, Ty);
142+
}
129143
// Short-circuit unnecessary bitcasts.
130144
if (Op == Instruction::BitCast) {
131145
if (V->getType() == Ty)

llvm/unittests/Transforms/Utils/ScalarEvolutionExpanderTest.cpp

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,14 @@
2020
#include "llvm/IR/InstIterator.h"
2121
#include "llvm/IR/LLVMContext.h"
2222
#include "llvm/IR/Module.h"
23+
#include "llvm/IR/PatternMatch.h"
2324
#include "llvm/IR/Verifier.h"
2425
#include "gtest/gtest.h"
2526

2627
namespace llvm {
2728

29+
using namespace PatternMatch;
30+
2831
// We use this fixture to ensure that we clean up ScalarEvolution before
2932
// deleting the PassManager.
3033
class ScalarEvolutionExpanderTest : public testing::Test {
@@ -917,4 +920,53 @@ TEST_F(ScalarEvolutionExpanderTest, SCEVExpandNonAffineAddRec) {
917920
TestMatchingCanonicalIV(GetAR5, ARBitWidth);
918921
}
919922

923+
TEST_F(ScalarEvolutionExpanderTest, ExpandNonIntegralPtrWithNullBase) {
924+
LLVMContext C;
925+
SMDiagnostic Err;
926+
927+
std::unique_ptr<Module> M =
928+
parseAssemblyString("target datalayout = "
929+
"\"e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:"
930+
"128-n8:16:32:64-S128-ni:1-p2:32:8:8:32-ni:2\""
931+
"define float addrspace(1)* @test(i64 %offset) { "
932+
" %ptr = getelementptr inbounds float, float "
933+
"addrspace(1)* null, i64 %offset"
934+
" ret float addrspace(1)* %ptr"
935+
"}",
936+
Err, C);
937+
938+
assert(M && "Could not parse module?");
939+
assert(!verifyModule(*M) && "Must have been well formed!");
940+
941+
runWithSE(*M, "test", [&](Function &F, LoopInfo &LI, ScalarEvolution &SE) {
942+
auto &I = GetInstByName(F, "ptr");
943+
auto PtrPlus1 =
944+
SE.getAddExpr(SE.getSCEV(&I), SE.getConstant(I.getType(), 1));
945+
SCEVExpander Exp(SE, M->getDataLayout(), "expander");
946+
947+
Value *V = Exp.expandCodeFor(PtrPlus1, I.getType(), &I);
948+
I.replaceAllUsesWith(V);
949+
950+
// Check the expander created bitcast (gep i8* null, %offset).
951+
auto *Cast = dyn_cast<BitCastInst>(V);
952+
EXPECT_TRUE(Cast);
953+
EXPECT_EQ(Cast->getType(), I.getType());
954+
auto *GEP = dyn_cast<GetElementPtrInst>(Cast->getOperand(0));
955+
EXPECT_TRUE(GEP);
956+
EXPECT_TRUE(cast<Constant>(GEP->getPointerOperand())->isNullValue());
957+
EXPECT_EQ(cast<PointerType>(GEP->getPointerOperand()->getType())
958+
->getAddressSpace(),
959+
cast<PointerType>(I.getType())->getAddressSpace());
960+
961+
// Check the expander created the expected index computation: add (shl
962+
// %offset, 2), 1.
963+
Value *Arg;
964+
EXPECT_TRUE(
965+
match(GEP->getOperand(1),
966+
m_Add(m_Shl(m_Value(Arg), m_SpecificInt(2)), m_SpecificInt(1))));
967+
EXPECT_EQ(Arg, &*F.arg_begin());
968+
EXPECT_FALSE(verifyFunction(F, &errs()));
969+
});
970+
}
971+
920972
} // end namespace llvm

0 commit comments

Comments
 (0)