Skip to content

Commit 4a3e000

Browse files
authored
[IR] Handle trunc for ptrtoaddr(inttoptr) cast pair (#162842)
For ptrtoint(inttoptr) and ptrtoaddr(inttoptr), handle the case where the source and destination size do not match and convert to either zext or trunc. We can't do this if the middle size is smaller than both src/dest, because we'd have to perform an additional masking operation in that case. Most of these cases are handled by dint of ptrtoint/inttoptr size canonicalization (so I added some unit tests instead). However, the ptrtoaddr(inttoptr) case where the pointer size and address size differ is relevant, as in that case the mismatch in integer sizes is canonical.
1 parent ea25153 commit 4a3e000

File tree

3 files changed

+50
-11
lines changed

3 files changed

+50
-11
lines changed

llvm/lib/IR/Instructions.cpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2965,19 +2965,23 @@ unsigned CastInst::isEliminableCastPair(Instruction::CastOps firstOp,
29652965
// zext, sext -> zext, because sext can't sign extend after zext
29662966
return Instruction::ZExt;
29672967
case 11: {
2968-
// inttoptr, ptrtoint/ptrtoaddr -> bitcast if SrcSize<=PtrSize/AddrSize
2969-
// and SrcSize==DstSize
2968+
// inttoptr, ptrtoint/ptrtoaddr -> integer cast
29702969
if (!DL)
29712970
return 0;
29722971
unsigned MidSize = secondOp == Instruction::PtrToAddr
29732972
? DL->getAddressSizeInBits(MidTy)
29742973
: DL->getPointerTypeSizeInBits(MidTy);
29752974
unsigned SrcSize = SrcTy->getScalarSizeInBits();
29762975
unsigned DstSize = DstTy->getScalarSizeInBits();
2977-
// TODO: Could also produce zext or trunc here.
2978-
if (SrcSize <= MidSize && SrcSize == DstSize)
2979-
return Instruction::BitCast;
2980-
return 0;
2976+
// If the middle size is smaller than both source and destination,
2977+
// an additional masking operation would be required.
2978+
if (MidSize < SrcSize && MidSize < DstSize)
2979+
return 0;
2980+
if (DstSize < SrcSize)
2981+
return Instruction::Trunc;
2982+
if (DstSize > SrcSize)
2983+
return Instruction::ZExt;
2984+
return Instruction::BitCast;
29812985
}
29822986
case 12:
29832987
// addrspacecast, addrspacecast -> bitcast, if SrcAS == DstAS

llvm/test/Transforms/InstCombine/ptrtoaddr.ll

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,7 @@ define i64 @ptrtoaddr_inttoptr_arg(i64 %a) {
2323
define i32 @ptrtoaddr_inttoptr_arg_addrsize(i32 %a) {
2424
; CHECK-LABEL: define i32 @ptrtoaddr_inttoptr_arg_addrsize(
2525
; CHECK-SAME: i32 [[A:%.*]]) {
26-
; CHECK-NEXT: [[TMP1:%.*]] = zext i32 [[A]] to i64
27-
; CHECK-NEXT: [[TOPTR:%.*]] = inttoptr i64 [[TMP1]] to ptr addrspace(1)
28-
; CHECK-NEXT: [[TOADDR:%.*]] = ptrtoaddr ptr addrspace(1) [[TOPTR]] to i32
29-
; CHECK-NEXT: ret i32 [[TOADDR]]
26+
; CHECK-NEXT: ret i32 [[A]]
3027
;
3128
%toptr = inttoptr i32 %a to ptr addrspace(1)
3229
%toaddr = ptrtoaddr ptr addrspace(1) %toptr to i32

llvm/unittests/IR/InstructionsTest.cpp

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -606,12 +606,14 @@ TEST(InstructionTest, ConstrainedTrans) {
606606

607607
TEST(InstructionsTest, isEliminableCastPair) {
608608
LLVMContext C;
609-
DataLayout DL1("p1:32:32");
609+
DataLayout DL1("p1:32:32-p2:64:64:64:32");
610610

611611
Type *Int16Ty = Type::getInt16Ty(C);
612+
Type *Int32Ty = Type::getInt32Ty(C);
612613
Type *Int64Ty = Type::getInt64Ty(C);
613614
Type *PtrTy64 = PointerType::get(C, 0);
614615
Type *PtrTy32 = PointerType::get(C, 1);
616+
Type *PtrTy64_32 = PointerType::get(C, 2);
615617

616618
// Source and destination pointers have same size -> bitcast.
617619
EXPECT_EQ(CastInst::isEliminableCastPair(CastInst::PtrToInt,
@@ -637,6 +639,42 @@ TEST(InstructionsTest, isEliminableCastPair) {
637639
Int64Ty, &DL1),
638640
0U);
639641

642+
// Destination larger than source. Pointer type same as destination.
643+
EXPECT_EQ(CastInst::isEliminableCastPair(CastInst::IntToPtr,
644+
CastInst::PtrToInt, Int16Ty, PtrTy64,
645+
Int64Ty, &DL1),
646+
CastInst::ZExt);
647+
648+
// Destination larger than source. Pointer type different from destination.
649+
EXPECT_EQ(CastInst::isEliminableCastPair(CastInst::IntToPtr,
650+
CastInst::PtrToInt, Int16Ty, PtrTy32,
651+
Int64Ty, &DL1),
652+
CastInst::ZExt);
653+
654+
// Destination smaller than source. Pointer type same as source.
655+
EXPECT_EQ(CastInst::isEliminableCastPair(CastInst::IntToPtr,
656+
CastInst::PtrToInt, Int64Ty, PtrTy64,
657+
Int16Ty, &DL1),
658+
CastInst::Trunc);
659+
660+
// Destination smaller than source. Pointer type different from source.
661+
EXPECT_EQ(CastInst::isEliminableCastPair(CastInst::IntToPtr,
662+
CastInst::PtrToInt, Int64Ty, PtrTy32,
663+
Int16Ty, &DL1),
664+
CastInst::Trunc);
665+
666+
// ptrtoaddr with address size != pointer size. Truncating case.
667+
EXPECT_EQ(CastInst::isEliminableCastPair(CastInst::IntToPtr,
668+
CastInst::PtrToAddr, Int64Ty,
669+
PtrTy64_32, Int32Ty, &DL1),
670+
CastInst::Trunc);
671+
672+
// ptrtoaddr with address size != pointer size. Non-truncating case.
673+
EXPECT_EQ(CastInst::isEliminableCastPair(CastInst::IntToPtr,
674+
CastInst::PtrToAddr, Int32Ty,
675+
PtrTy64_32, Int32Ty, &DL1),
676+
CastInst::BitCast);
677+
640678
// Test that we don't eliminate bitcasts between different address spaces,
641679
// or if we don't have available pointer size information.
642680
DataLayout DL2("e-p:32:32:32-p1:16:16:16-p2:64:64:64-i1:8:8-i8:8:8-i16:16:16"

0 commit comments

Comments
 (0)