# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
# RUN: llc -mtriple aarch64-apple-darwin -run-pass=aarch64-prelegalizer-combiner -verify-machineinstrs %s -o - | FileCheck %s
--- |
@g = external hidden global i32
%opaque = type opaque
@unsized = external hidden global %opaque
@thread_local = thread_local global i32 0
define void @one_ptr_add() { ret void }
define void @add_to_offset() { ret void }
define void @two_ptr_adds_same_offset() { ret void }
define void @two_ptr_adds_different_offset() { ret void }
define void @ptr_add_chain() { ret void }
define void @dont_fold_negative_offset() { ret void }
define void @dont_min_offset_less_than_curr_offset() { ret void }
define void @dont_fold_max_offset() { ret void }
define void @dont_fold_offset_larger_than_type_alloc() { ret void }
define void @dont_fold_unsized_type() { ret void }
define void @dont_fold_thread_local() { ret void }
...
# We should fold the offset 1 into the G_GLOBAL_VALUE.
---
name: one_ptr_add
alignment: 4
tracksRegLiveness: true
machineFunctionInfo: {}
body: |
bb.0:
liveins: $x0
; CHECK-LABEL: name: one_ptr_add
; CHECK: liveins: $x0
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[GV:%[0-9]+]]:_(p0) = G_GLOBAL_VALUE @g + 1
; CHECK-NEXT: $x0 = COPY [[GV]](p0)
; CHECK-NEXT: RET_ReallyLR implicit $x0
%global:_(p0) = G_GLOBAL_VALUE @g
%offset:_(s64) = G_CONSTANT i64 1
%ptr_add:_(p0) = G_PTR_ADD %global, %offset(s64)
$x0 = COPY %ptr_add
RET_ReallyLR implicit $x0
...
# We should fold the offset 1 into the G_GLOBAL_VALUE, resulting in a
# final offset of 4.
---
name: add_to_offset
alignment: 4
tracksRegLiveness: true
machineFunctionInfo: {}
body: |
bb.0:
liveins: $x0
; CHECK-LABEL: name: add_to_offset
; CHECK: liveins: $x0
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[GV:%[0-9]+]]:_(p0) = G_GLOBAL_VALUE @g + 4
; CHECK-NEXT: $x0 = COPY [[GV]](p0)
; CHECK-NEXT: RET_ReallyLR implicit $x0
%global:_(p0) = G_GLOBAL_VALUE @g + 3
%offset:_(s64) = G_CONSTANT i64 1
%ptr_add:_(p0) = G_PTR_ADD %global, %offset(s64)
$x0 = COPY %ptr_add
RET_ReallyLR implicit $x0
...
# We're allowed to have more than one G_PTR_ADD use. We should fold 1 into
# the G_GLOBAL_VALUE's offset.
---
name: two_ptr_adds_same_offset
alignment: 4
tracksRegLiveness: true
machineFunctionInfo: {}
body: |
bb.0:
liveins: $x0, $x1
; CHECK-LABEL: name: two_ptr_adds_same_offset
; CHECK: liveins: $x0, $x1
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: %val1:_(s64) = COPY $x0
; CHECK-NEXT: %val2:_(s64) = COPY $x1
; CHECK-NEXT: [[GV:%[0-9]+]]:_(p0) = G_GLOBAL_VALUE @g + 1
; CHECK-NEXT: G_STORE %val1(s64), [[GV]](p0) :: (store (s64))
; CHECK-NEXT: G_STORE %val2(s64), [[GV]](p0) :: (store (s64))
; CHECK-NEXT: RET_ReallyLR implicit $x0
%val1:_(s64) = COPY $x0
%val2:_(s64) = COPY $x1
%global:_(p0) = G_GLOBAL_VALUE @g
%offset:_(s64) = G_CONSTANT i64 1
%ptr_add1:_(p0) = G_PTR_ADD %global, %offset(s64)
%ptr_add2:_(p0) = G_PTR_ADD %global, %offset(s64)
G_STORE %val1:_(s64), %ptr_add1 :: (store (s64))
G_STORE %val2:_(s64), %ptr_add2 :: (store (s64))
RET_ReallyLR implicit $x0
...
# The lowest offset G_PTR_ADD (2) should be folded into the G_GLOBAL_VALUE.
#
# The other G_PTR_ADD should have its offset decremented by 2.
---
name: two_ptr_adds_different_offset
alignment: 4
tracksRegLiveness: true
machineFunctionInfo: {}
body: |
bb.0:
liveins: $x0, $x1
; CHECK-LABEL: name: two_ptr_adds_different_offset
; CHECK: liveins: $x0, $x1
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: %val1:_(s64) = COPY $x0
; CHECK-NEXT: %val2:_(s64) = COPY $x1
; CHECK-NEXT: [[GV:%[0-9]+]]:_(p0) = G_GLOBAL_VALUE @g + 2
; CHECK-NEXT: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 8
; CHECK-NEXT: %ptr_add2:_(p0) = G_PTR_ADD [[GV]], [[C]](s64)
; CHECK-NEXT: G_STORE %val1(s64), [[GV]](p0) :: (store (s64))
; CHECK-NEXT: G_STORE %val2(s64), %ptr_add2(p0) :: (store (s64))
; CHECK-NEXT: RET_ReallyLR implicit $x0
%val1:_(s64) = COPY $x0
%val2:_(s64) = COPY $x1
%global:_(p0) = G_GLOBAL_VALUE @g
%offset1:_(s64) = G_CONSTANT i64 2
%offset2:_(s64) = G_CONSTANT i64 10
%ptr_add1:_(p0) = G_PTR_ADD %global, %offset1(s64)
%ptr_add2:_(p0) = G_PTR_ADD %global, %offset2(s64)
G_STORE %val1:_(s64), %ptr_add1 :: (store (s64))
G_STORE %val2:_(s64), %ptr_add2 :: (store (s64))
RET_ReallyLR implicit $x0
...
# We should be able to fold all of the G_PTR_ADDs, except for the last one
# into the G_GLOBAL_VALUE.
#
# (TypeAllocSize = 4, so the offset on the G_GLOBAL_VALUE can't go above
# that.)
---
name: ptr_add_chain
alignment: 4
tracksRegLiveness: true
machineFunctionInfo: {}
body: |
bb.0:
liveins: $x0
; CHECK-LABEL: name: ptr_add_chain
; CHECK: liveins: $x0
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[GV:%[0-9]+]]:_(p0) = G_GLOBAL_VALUE @g + 4
; CHECK-NEXT: %offset:_(s64) = G_CONSTANT i64 1
; CHECK-NEXT: %dont_fold_me:_(p0) = G_PTR_ADD [[GV]], %offset(s64)
; CHECK-NEXT: $x0 = COPY %dont_fold_me(p0)
; CHECK-NEXT: RET_ReallyLR implicit $x0
%global:_(p0) = G_GLOBAL_VALUE @g
%offset:_(s64) = G_CONSTANT i64 1
%ptr_add1:_(p0) = G_PTR_ADD %global, %offset(s64)
%ptr_add2:_(p0) = G_PTR_ADD %ptr_add1, %offset(s64)
%ptr_add3:_(p0) = G_PTR_ADD %ptr_add2, %offset(s64)
%ptr_add4:_(p0) = G_PTR_ADD %ptr_add3, %offset(s64)
%dont_fold_me:_(p0) = G_PTR_ADD %ptr_add4, %offset(s64)
$x0 = COPY %dont_fold_me
RET_ReallyLR implicit $x0
...
# Do not add negative offsets to G_GLOBAL_VALUE.
---
name: dont_fold_negative_offset
alignment: 4
tracksRegLiveness: true
machineFunctionInfo: {}
body: |
bb.0:
liveins: $x0
; CHECK-LABEL: name: dont_fold_negative_offset
; CHECK: liveins: $x0
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: %global:_(p0) = G_GLOBAL_VALUE @g
; CHECK-NEXT: %offset:_(s64) = G_CONSTANT i64 -1
; CHECK-NEXT: %ptr_add:_(p0) = G_PTR_ADD %global, %offset(s64)
; CHECK-NEXT: $x0 = COPY %ptr_add(p0)
; CHECK-NEXT: RET_ReallyLR implicit $x0
%global:_(p0) = G_GLOBAL_VALUE @g
%offset:_(s64) = G_CONSTANT i64 -1
%ptr_add:_(p0) = G_PTR_ADD %global, %offset(s64)
$x0 = COPY %ptr_add
RET_ReallyLR implicit $x0
...
# Do not create smaller offsets. Ensures combine termination.
---
name: dont_min_offset_less_than_curr_offset
alignment: 4
tracksRegLiveness: true
machineFunctionInfo: {}
body: |
bb.0:
liveins: $x0
; CHECK-LABEL: name: dont_min_offset_less_than_curr_offset
; CHECK: liveins: $x0
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: %global:_(p0) = G_GLOBAL_VALUE @g + 3
; CHECK-NEXT: %offset:_(s64) = G_CONSTANT i64 -1
; CHECK-NEXT: %ptr_add:_(p0) = G_PTR_ADD %global, %offset(s64)
; CHECK-NEXT: $x0 = COPY %ptr_add(p0)
; CHECK-NEXT: RET_ReallyLR implicit $x0
%global:_(p0) = G_GLOBAL_VALUE @g + 3
%offset:_(s64) = G_CONSTANT i64 -1
%ptr_add:_(p0) = G_PTR_ADD %global, %offset(s64)
$x0 = COPY %ptr_add
RET_ReallyLR implicit $x0
...
# 1 << 21 is the largest offset expressible in all object formats.
# Don't fold it.
---
name: dont_fold_max_offset
alignment: 4
tracksRegLiveness: true
machineFunctionInfo: {}
body: |
bb.0:
liveins: $x0
; CHECK-LABEL: name: dont_fold_max_offset
; CHECK: liveins: $x0
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: %global:_(p0) = G_GLOBAL_VALUE @g
; CHECK-NEXT: %offset:_(s64) = G_CONSTANT i64 4292870144
; CHECK-NEXT: %ptr_add:_(p0) = G_PTR_ADD %global, %offset(s64)
; CHECK-NEXT: $x0 = COPY %ptr_add(p0)
; CHECK-NEXT: RET_ReallyLR implicit $x0
%global:_(p0) = G_GLOBAL_VALUE @g
%offset:_(s64) = G_CONSTANT i64 4292870144 ; 1 << 21
%ptr_add:_(p0) = G_PTR_ADD %global, %offset(s64)
$x0 = COPY %ptr_add
RET_ReallyLR implicit $x0
...
# Type alloc size = 4, offset = 16. Don't fold.
---
name: dont_fold_offset_larger_than_type_alloc
alignment: 4
tracksRegLiveness: true
machineFunctionInfo: {}
body: |
bb.0:
; CHECK-LABEL: name: dont_fold_offset_larger_than_type_alloc
; CHECK: %global:_(p0) = G_GLOBAL_VALUE @g
; CHECK-NEXT: %offset:_(s64) = G_CONSTANT i64 16
; CHECK-NEXT: %ptr_add:_(p0) = G_PTR_ADD %global, %offset(s64)
; CHECK-NEXT: $x0 = COPY %ptr_add(p0)
; CHECK-NEXT: RET_ReallyLR implicit $x0
%global:_(p0) = G_GLOBAL_VALUE @g
%offset:_(s64) = G_CONSTANT i64 16
%ptr_add:_(p0) = G_PTR_ADD %global, %offset(s64)
$x0 = COPY %ptr_add(p0)
RET_ReallyLR implicit $x0
...
# Check that we don't touch unsized globals.
---
name: dont_fold_unsized_type
alignment: 4
tracksRegLiveness: true
machineFunctionInfo: {}
body: |
bb.0:
; CHECK-LABEL: name: dont_fold_unsized_type
; CHECK: %global:_(p0) = G_GLOBAL_VALUE @unsized
; CHECK-NEXT: %offset:_(s64) = G_CONSTANT i64 16
; CHECK-NEXT: %ptr_add:_(p0) = G_PTR_ADD %global, %offset(s64)
; CHECK-NEXT: $x0 = COPY %ptr_add(p0)
; CHECK-NEXT: RET_ReallyLR implicit $x0
%global:_(p0) = G_GLOBAL_VALUE @unsized
%offset:_(s64) = G_CONSTANT i64 16
%ptr_add:_(p0) = G_PTR_ADD %global, %offset(s64)
$x0 = COPY %ptr_add(p0)
RET_ReallyLR implicit $x0
...
# Check that we don't touch thread-local globals.
---
name: dont_fold_thread_local
alignment: 4
tracksRegLiveness: true
machineFunctionInfo: {}
body: |
bb.0:
; CHECK-LABEL: name: dont_fold_thread_local
; CHECK: %global:_(p0) = G_GLOBAL_VALUE @thread_local
; CHECK-NEXT: %offset:_(s64) = G_CONSTANT i64 16
; CHECK-NEXT: %ptr_add:_(p0) = G_PTR_ADD %global, %offset(s64)
; CHECK-NEXT: $x0 = COPY %ptr_add(p0)
; CHECK-NEXT: RET_ReallyLR implicit $x0
%global:_(p0) = G_GLOBAL_VALUE @thread_local
%offset:_(s64) = G_CONSTANT i64 16
%ptr_add:_(p0) = G_PTR_ADD %global, %offset(s64)
$x0 = COPY %ptr_add(p0)
RET_ReallyLR implicit $x0