Unverified Commit a6492e22 authored by Roman Lebedev's avatar Roman Lebedev
Browse files

[IR] Value::getPointerAlignment(): handle pointer constants

Summary:
New `@test13` in `Attributor/align.ll` is the main motivation - `null` pointer
really does not limit our alignment knowledge, in fact it is fully aligned
since it has no bits set.

Here we don't special-case `null` pointer because it is somewhat controversial
to add one more place where we enforce that `null` pointer is zero,
but instead we do the more general thing of trying to perform constant-fold
of pointer constant to an integer, and perform alignment inferrment on that.

Reviewers: jdoerfert, gchatelet, courbet, sstefan1

Reviewed By: jdoerfert

Subscribers: hiraditya, arphaman, jfb, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D73131
parent f42994f2
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -729,6 +729,17 @@ MaybeAlign Value::getPointerAlignment(const DataLayout &DL) const {
      ConstantInt *CI = mdconst::extract<ConstantInt>(MD->getOperand(0));
      return MaybeAlign(CI->getLimitedValue());
    }
  } else if (auto *CstPtr = dyn_cast<Constant>(this)) {
    if (auto *CstInt = dyn_cast_or_null<ConstantInt>(ConstantExpr::getPtrToInt(
            const_cast<Constant *>(CstPtr), DL.getIntPtrType(getType()),
            /*OnlyIfReduced=*/true))) {
      size_t TrailingZeros = CstInt->getValue().countTrailingZeros();
      // While the actual alignment may be large, elsewhere we have
      // an arbitrary upper alignmet limit, so let's clamp to it.
      return Align(TrailingZeros < Value::MaxAlignmentExponent
                       ? uint64_t(1) << TrailingZeros
                       : Value::MaximumAlignment);
    }
  }
  return llvm::None;
}
+3 −3
Original line number Diff line number Diff line
@@ -6,9 +6,9 @@
; because there is a load of %A in the entry block
define internal i32 @callee(i1 %C, i32* %A) {
; CHECK-LABEL: define {{[^@]+}}@callee
; CHECK-SAME: (i1 [[C:%.*]], i32* noalias nocapture nofree nonnull readonly dereferenceable(4) [[A:%.*]])
; CHECK-SAME: (i1 [[C:%.*]], i32* noalias nocapture nofree nonnull readonly align 536870912 dereferenceable(4) [[A:%.*]])
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[A_0:%.*]] = load i32, i32* null
; CHECK-NEXT:    [[A_0:%.*]] = load i32, i32* null, align 536870912
; CHECK-NEXT:    br label [[F:%.*]]
; CHECK:       T:
; CHECK-NEXT:    unreachable
@@ -34,7 +34,7 @@ F:

define i32 @foo() {
; CHECK-LABEL: define {{[^@]+}}@foo()
; CHECK-NEXT:    [[X:%.*]] = call i32 @callee(i1 false, i32* noalias nofree readonly null)
; CHECK-NEXT:    [[X:%.*]] = call i32 @callee(i1 false, i32* noalias nofree readonly align 536870912 null)
; CHECK-NEXT:    ret i32 [[X]]
;
  %X = call i32 @callee(i1 false, i32* null)             ; <i32> [#uses=1]
+5 −5
Original line number Diff line number Diff line
@@ -33,10 +33,10 @@ define dso_local i32 @main() {
; CHECK-NEXT:    [[ALLOC1:%.*]] = alloca i8, align 8
; CHECK-NEXT:    [[ALLOC2:%.*]] = alloca i8, align 8
; CHECK-NEXT:    [[THREAD:%.*]] = alloca i64, align 8
; CHECK-NEXT:    [[CALL:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias null, i8* (i8*)* nonnull @foo, i8* noalias nofree readnone null)
; CHECK-NEXT:    [[CALL1:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias null, i8* (i8*)* nonnull @bar, i8* nofree nonnull readnone align 8 dereferenceable(8) bitcast (i8** @GlobalVPtr to i8*))
; CHECK-NEXT:    [[CALL2:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias null, i8* (i8*)* nonnull @baz, i8* noalias nocapture nofree nonnull readnone align 8 dereferenceable(1) [[ALLOC1]])
; CHECK-NEXT:    [[CALL3:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias null, i8* (i8*)* nonnull @buz, i8* nofree nonnull readnone align 8 dereferenceable(1) [[ALLOC2]])
; CHECK-NEXT:    [[CALL:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias align 536870912 null, i8* (i8*)* nonnull @foo, i8* noalias nofree readnone align 536870912 null)
; CHECK-NEXT:    [[CALL1:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias align 536870912 null, i8* (i8*)* nonnull @bar, i8* nofree nonnull readnone align 8 dereferenceable(8) bitcast (i8** @GlobalVPtr to i8*))
; CHECK-NEXT:    [[CALL2:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias align 536870912 null, i8* (i8*)* nonnull @baz, i8* noalias nocapture nofree nonnull readnone align 8 dereferenceable(1) [[ALLOC1]])
; CHECK-NEXT:    [[CALL3:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias align 536870912 null, i8* (i8*)* nonnull @buz, i8* nofree nonnull readnone align 8 dereferenceable(1) [[ALLOC2]])
; CHECK-NEXT:    ret i32 0
;
entry:
@@ -54,7 +54,7 @@ declare !callback !0 dso_local i32 @pthread_create(i64*, %union.pthread_attr_t*,

define internal i8* @foo(i8* %arg) {
; CHECK-LABEL: define {{[^@]+}}@foo
; CHECK-SAME: (i8* noalias nofree readnone returned [[ARG:%.*]])
; CHECK-SAME: (i8* noalias nofree readnone returned align 536870912 [[ARG:%.*]])
; CHECK-NEXT:  entry:
; CHECK-NEXT:    ret i8* null
;
+94 −0
Original line number Diff line number Diff line
@@ -398,6 +398,99 @@ define void @test12-6(i32* align 4 %p) {
  ret void
}

define void @test13(i1 %c, i32* align 32 %dst) #0 {
; ATTRIBUTOR-LABEL: define {{[^@]+}}@test13
; ATTRIBUTOR-SAME: (i1 [[C:%.*]], i32* nocapture nofree writeonly align 32 [[DST:%.*]])
; ATTRIBUTOR-NEXT:    br i1 [[C]], label [[TRUEBB:%.*]], label [[FALSEBB:%.*]]
; ATTRIBUTOR:       truebb:
; ATTRIBUTOR-NEXT:    br label [[END:%.*]]
; ATTRIBUTOR:       falsebb:
; ATTRIBUTOR-NEXT:    br label [[END]]
; ATTRIBUTOR:       end:
; ATTRIBUTOR-NEXT:    [[PTR:%.*]] = phi i32* [ [[DST]], [[TRUEBB]] ], [ null, [[FALSEBB]] ]
; ATTRIBUTOR-NEXT:    store i32 0, i32* [[PTR]], align 32
; ATTRIBUTOR-NEXT:    ret void
;
  br i1 %c, label %truebb, label %falsebb
truebb:
  br label %end
falsebb:
  br label %end
end:
  %ptr = phi i32* [ %dst, %truebb ], [ null, %falsebb ]
  store i32 0, i32* %ptr
  ret void
}

define void @test13-1(i1 %c, i32* align 32 %dst) {
; ATTRIBUTOR-LABEL: @test13-1(
; ATTRIBUTOR-NEXT:    br i1 [[C:%.*]], label [[TRUEBB:%.*]], label [[FALSEBB:%.*]]
; ATTRIBUTOR:       truebb:
; ATTRIBUTOR-NEXT:    br label [[END:%.*]]
; ATTRIBUTOR:       falsebb:
; ATTRIBUTOR-NEXT:    br label [[END]]
; ATTRIBUTOR:       end:
; ATTRIBUTOR-NEXT:    [[PTR:%.*]] = phi i32* [ [[DST:%.*]], [[TRUEBB]] ], [ inttoptr (i64 48 to i32*), [[FALSEBB]] ]
; ATTRIBUTOR-NEXT:    store i32 0, i32* [[PTR]], align 16
; ATTRIBUTOR-NEXT:    ret void
;
  br i1 %c, label %truebb, label %falsebb
truebb:
  br label %end
falsebb:
  br label %end
end:
  %ptr = phi i32* [ %dst, %truebb ], [ inttoptr (i64 48 to i32*), %falsebb ]
  store i32 0, i32* %ptr
  ret void
}

define void @test13-2(i1 %c, i32* align 32 %dst) {
; ATTRIBUTOR-LABEL: @test13-2(
; ATTRIBUTOR-NEXT:    br i1 [[C:%.*]], label [[TRUEBB:%.*]], label [[FALSEBB:%.*]]
; ATTRIBUTOR:       truebb:
; ATTRIBUTOR-NEXT:    br label [[END:%.*]]
; ATTRIBUTOR:       falsebb:
; ATTRIBUTOR-NEXT:    br label [[END]]
; ATTRIBUTOR:       end:
; ATTRIBUTOR-NEXT:    [[PTR:%.*]] = phi i32* [ [[DST:%.*]], [[TRUEBB]] ], [ inttoptr (i64 160 to i32*), [[FALSEBB]] ]
; ATTRIBUTOR-NEXT:    store i32 0, i32* [[PTR]], align 32
; ATTRIBUTOR-NEXT:    ret void
;
  br i1 %c, label %truebb, label %falsebb
truebb:
  br label %end
falsebb:
  br label %end
end:
  %ptr = phi i32* [ %dst, %truebb ], [ inttoptr (i64 160 to i32*), %falsebb ]
  store i32 0, i32* %ptr
  ret void
}

define void @test13-3(i1 %c, i32* align 32 %dst) {
; ATTRIBUTOR-LABEL: @test13-3(
; ATTRIBUTOR-NEXT:    br i1 [[C:%.*]], label [[TRUEBB:%.*]], label [[FALSEBB:%.*]]
; ATTRIBUTOR:       truebb:
; ATTRIBUTOR-NEXT:    br label [[END:%.*]]
; ATTRIBUTOR:       falsebb:
; ATTRIBUTOR-NEXT:    br label [[END]]
; ATTRIBUTOR:       end:
; ATTRIBUTOR-NEXT:    [[PTR:%.*]] = phi i32* [ [[DST:%.*]], [[TRUEBB]] ], [ inttoptr (i64 128 to i32*), [[FALSEBB]] ]
; ATTRIBUTOR-NEXT:    store i32 0, i32* [[PTR]], align 32
; ATTRIBUTOR-NEXT:    ret void
;
  br i1 %c, label %truebb, label %falsebb
truebb:
  br label %end
falsebb:
  br label %end
end:
  %ptr = phi i32* [ %dst, %truebb ], [ inttoptr (i64 128 to i32*), %falsebb ]
  store i32 0, i32* %ptr
  ret void
}

; Don't crash on ptr2int/int2ptr uses.
define i64 @ptr2int(i32* %p) {
  %p2i = ptrtoint i32* %p to i64
@@ -410,3 +503,4 @@ define i64* @int2ptr(i64 %i) {

attributes #0 = { nounwind uwtable noinline }
attributes #1 = { uwtable noinline }
attributes #2 = { "null-pointer-is-valid"="true" }
+9 −8
Original line number Diff line number Diff line
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
; FIXME: Add -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations below.
;        This flag was removed because max iterations is 2 in most cases, but in windows it is 1.
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-annotate-decl-cs < %s | FileCheck %s
@@ -15,7 +15,8 @@ target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16
; transfer in both directions.

define void @t0_caller(i32* %a) {
; CHECK-LABEL: @t0_caller(
; CHECK-LABEL: define {{[^@]+}}@t0_caller
; CHECK-SAME: (i32* align 256 [[A:%.*]])
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[B:%.*]] = alloca i32, align 32
; CHECK-NEXT:    [[C:%.*]] = alloca i32*, align 64
@@ -23,10 +24,10 @@ define void @t0_caller(i32* %a) {
; CHECK-NEXT:    [[TMP0:%.*]] = bitcast i32* [[B]] to i8*
; CHECK-NEXT:    store i32 42, i32* [[B]], align 32
; CHECK-NEXT:    store i32* [[B]], i32** [[C]], align 64
; CHECK-NEXT:    call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t0_callback_broker(i32* noalias null, i32* nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* nonnull bitcast (void (i32*, i32*, i32*, i64, i32**)* @t0_callback_callee to void (i32*, i32*, ...)*), i32* align 256 [[A:%.*]], i64 99, i32** noalias nocapture nonnull readonly align 64 dereferenceable(8) [[C]])

; CHECK-NEXT:    call void (i32*, i32*, void (i32*, i32*, ...)*, ...) @t0_callback_broker(i32* noalias align 536870912 null, i32* nonnull align 128 dereferenceable(4) [[PTR]], void (i32*, i32*, ...)* nonnull bitcast (void (i32*, i32*, i32*, i64, i32**)* @t0_callback_callee to void (i32*, i32*, ...)*), i32* align 256 [[A]], i64 99, i32** noalias nocapture nonnull readonly align 64 dereferenceable(8) [[C]])
; CHECK-NEXT:    ret void
;

entry:
  %b = alloca i32, align 32
  %c = alloca i32*, align 64
@@ -44,10 +45,10 @@ define internal void @t0_callback_callee(i32* %is_not_null, i32* %ptr, i32* %a,
; CHECK-LABEL: define {{[^@]+}}@t0_callback_callee
; CHECK-SAME: (i32* nocapture nonnull writeonly dereferenceable(4) [[IS_NOT_NULL:%.*]], i32* nocapture nonnull readonly align 8 dereferenceable(4) [[PTR:%.*]], i32* align 256 [[A:%.*]], i64 [[B:%.*]], i32** noalias nocapture nonnull readonly align 64 dereferenceable(8) [[C:%.*]])
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[PTR_VAL:%.*]] = load i32, i32* [[PTR:%.*]], align 8
; CHECK-NEXT:    store i32 [[PTR_VAL]], i32* [[IS_NOT_NULL:%.*]]
; CHECK-NEXT:    [[TMP0:%.*]] = load i32*, i32** [[C:%.*]], align 64
; CHECK-NEXT:    tail call void @t0_check(i32* align 256 [[A:%.*]], i64 99, i32* [[TMP0]])
; CHECK-NEXT:    [[PTR_VAL:%.*]] = load i32, i32* [[PTR]], align 8
; CHECK-NEXT:    store i32 [[PTR_VAL]], i32* [[IS_NOT_NULL]]
; CHECK-NEXT:    [[TMP0:%.*]] = load i32*, i32** [[C]], align 64
; CHECK-NEXT:    tail call void @t0_check(i32* align 256 [[A]], i64 99, i32* [[TMP0]])
; CHECK-NEXT:    ret void
;
entry:
Loading