This commit adds the -lower-buffer-fat-pointers pass, which is
applicable to all AMDGCN compilations.
The purpose of this pass is to remove the type `ptr addrspace(7)` from
incoming IR. This must be done at the LLVM IR level because `ptr
addrspace(7)`, as a 160-bit primitive type, cannot be correctly handled
by SelectionDAG.
The detailed operation of the pass is described in comments, but, in
summary, the removal proceeds by:
1. Rewriting loads and stores of ptr addrspace(7) to loads and stores of
i160 (including vectors and aggregates). This is needed because the
in-register representation of these pointers will stop matching their
in-memory representation in step 2, and so ptrtoint/inttoptr operations
are used to preserve the expected memory layout
2. Mutating the IR to replace all occurrences of `ptr addrspace(7)` with
the type `{ptr addrspace(8), ptr addrspace(6) }`, which makes the two
parts of a buffer fat pointer (the 128-bit address space 8 resource and
the 32-bit address space 6 offset) visible in the IR. This also impacts
the argument and return types of functions.
3. *Splitting* the resource and offset parts. All instructions that
produce or consume buffer fat pointers (like GEP or load) are rewritten
to produce or consume the resource and offset parts separately. For
example, GEP updates the offset part of the result and a load uses the
resource and offset parts to populate the relevant
llvm.amdgcn.raw.ptr.buffer.load intrinsic call.
At the end of this process, the original mutated instructions are
replaced by their new split counterparts, ensuring no invalidly-typed IR
escapes this pass. (For operations like call, where the struct form is
needed, insertelement operations are inserted).
Compared to LGC's PatchBufferOp (
32cda89776/lgc/patch/PatchBufferOp.cpp
): this pass
- Also handles vectors of ptr addrspace(7)s
- Also handles function boundaries
- Includes the same uniform buffer optimization for loops and
conditionals
- Does *not* handle memcpy() and friends (this is future work)
- Does *not* break up large loads and stores into smaller parts. This
should be handled by extending the legalization
of *.buffer.{load,store} to handle larger types by producing multiple
instructions (the same way ordinary LOAD and STORE are legalized). That
work is planned for a followup commit.
- Does *not* have special logic for handling divergent buffer
descriptors. The logic in LGC is, as far as I can tell, incorrect in
general, and, per discussions with @nhaehnle, isn't widely used.
Therefore, divergent descriptors are handled with waterfall loops later
in legalization.
As a final matter, this commit updates atomic expansion to treat buffer
operations analogously to global ones.
(One question for reviewers: is the new pass is the right place? Should
it be later in the pipeline?)
Differential Revision: https://reviews.llvm.org/D158463
481 lines
27 KiB
LLVM
481 lines
27 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
|
|
; RUN: opt -S -mcpu=gfx900 -amdgpu-lower-buffer-fat-pointers < %s | FileCheck %s
|
|
; RUN: opt -S -mcpu=gfx900 -passes=amdgpu-lower-buffer-fat-pointers < %s | FileCheck %s
|
|
|
|
target datalayout = "e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32:32-p7:160:256:256:32-p8:128:128-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-S32-A5-G1-ni:7:8"
|
|
target triple = "amdgcn--"
|
|
|
|
define ptr addrspace(7) @gep(ptr addrspace(7) %in, i32 %idx) {
|
|
; CHECK-LABEL: define { ptr addrspace(8), i32 } @gep
|
|
; CHECK-SAME: ({ ptr addrspace(8), i32 } [[IN:%.*]], i32 [[IDX:%.*]]) #[[ATTR0:[0-9]+]] {
|
|
; CHECK-NEXT: [[IN_RSRC:%.*]] = extractvalue { ptr addrspace(8), i32 } [[IN]], 0
|
|
; CHECK-NEXT: [[IN_OFF:%.*]] = extractvalue { ptr addrspace(8), i32 } [[IN]], 1
|
|
; CHECK-NEXT: [[TMP1:%.*]] = mul nuw nsw i32 [[IDX]], 40
|
|
; CHECK-NEXT: [[TMP2:%.*]] = add nuw nsw i32 [[TMP1]], 32
|
|
; CHECK-NEXT: [[RET:%.*]] = add i32 [[IN_OFF]], [[TMP2]]
|
|
; CHECK-NEXT: [[TMP3:%.*]] = insertvalue { ptr addrspace(8), i32 } poison, ptr addrspace(8) [[IN_RSRC]], 0
|
|
; CHECK-NEXT: [[TMP4:%.*]] = insertvalue { ptr addrspace(8), i32 } [[TMP3]], i32 [[RET]], 1
|
|
; CHECK-NEXT: ret { ptr addrspace(8), i32 } [[TMP4]]
|
|
;
|
|
%ret = getelementptr inbounds {i32, [4 x ptr]}, ptr addrspace(7) %in, i32 %idx, i32 1, i32 3
|
|
ret ptr addrspace(7) %ret
|
|
}
|
|
|
|
define <2 x ptr addrspace(7)> @gep_vectors(<2 x ptr addrspace(7)> %in, <2 x i32> %idx) {
|
|
; CHECK-LABEL: define { <2 x ptr addrspace(8)>, <2 x i32> } @gep_vectors
|
|
; CHECK-SAME: ({ <2 x ptr addrspace(8)>, <2 x i32> } [[IN:%.*]], <2 x i32> [[IDX:%.*]]) #[[ATTR0]] {
|
|
; CHECK-NEXT: [[IN_RSRC:%.*]] = extractvalue { <2 x ptr addrspace(8)>, <2 x i32> } [[IN]], 0
|
|
; CHECK-NEXT: [[IN_OFF:%.*]] = extractvalue { <2 x ptr addrspace(8)>, <2 x i32> } [[IN]], 1
|
|
; CHECK-NEXT: [[TMP1:%.*]] = mul nuw nsw <2 x i32> [[IDX]], <i32 40, i32 40>
|
|
; CHECK-NEXT: [[TMP2:%.*]] = add nuw nsw <2 x i32> [[TMP1]], <i32 32, i32 32>
|
|
; CHECK-NEXT: [[RET:%.*]] = add <2 x i32> [[IN_OFF]], [[TMP2]]
|
|
; CHECK-NEXT: [[TMP3:%.*]] = insertvalue { <2 x ptr addrspace(8)>, <2 x i32> } poison, <2 x ptr addrspace(8)> [[IN_RSRC]], 0
|
|
; CHECK-NEXT: [[TMP4:%.*]] = insertvalue { <2 x ptr addrspace(8)>, <2 x i32> } [[TMP3]], <2 x i32> [[RET]], 1
|
|
; CHECK-NEXT: ret { <2 x ptr addrspace(8)>, <2 x i32> } [[TMP4]]
|
|
;
|
|
%ret = getelementptr inbounds {i32, [4 x ptr]}, <2 x ptr addrspace(7)> %in, <2 x i32> %idx, i32 1, i32 3
|
|
ret <2 x ptr addrspace(7)> %ret
|
|
}
|
|
|
|
define <2 x ptr addrspace(7)> @gep_vector_scalar(<2 x ptr addrspace(7)> %in, i64 %idx) {
|
|
; CHECK-LABEL: define { <2 x ptr addrspace(8)>, <2 x i32> } @gep_vector_scalar
|
|
; CHECK-SAME: ({ <2 x ptr addrspace(8)>, <2 x i32> } [[IN:%.*]], i64 [[IDX:%.*]]) #[[ATTR0]] {
|
|
; CHECK-NEXT: [[IN_RSRC:%.*]] = extractvalue { <2 x ptr addrspace(8)>, <2 x i32> } [[IN]], 0
|
|
; CHECK-NEXT: [[IN_OFF:%.*]] = extractvalue { <2 x ptr addrspace(8)>, <2 x i32> } [[IN]], 1
|
|
; CHECK-NEXT: [[DOTSPLATINSERT:%.*]] = insertelement <2 x i64> poison, i64 [[IDX]], i64 0
|
|
; CHECK-NEXT: [[DOTSPLAT:%.*]] = shufflevector <2 x i64> [[DOTSPLATINSERT]], <2 x i64> poison, <2 x i32> zeroinitializer
|
|
; CHECK-NEXT: [[TMP1:%.*]] = trunc <2 x i64> [[DOTSPLAT]] to <2 x i32>
|
|
; CHECK-NEXT: [[TMP2:%.*]] = mul nuw nsw <2 x i32> [[TMP1]], <i32 40, i32 40>
|
|
; CHECK-NEXT: [[TMP3:%.*]] = add nuw nsw <2 x i32> [[TMP2]], <i32 32, i32 32>
|
|
; CHECK-NEXT: [[RET:%.*]] = add <2 x i32> [[IN_OFF]], [[TMP3]]
|
|
; CHECK-NEXT: [[TMP4:%.*]] = insertvalue { <2 x ptr addrspace(8)>, <2 x i32> } poison, <2 x ptr addrspace(8)> [[IN_RSRC]], 0
|
|
; CHECK-NEXT: [[TMP5:%.*]] = insertvalue { <2 x ptr addrspace(8)>, <2 x i32> } [[TMP4]], <2 x i32> [[RET]], 1
|
|
; CHECK-NEXT: ret { <2 x ptr addrspace(8)>, <2 x i32> } [[TMP5]]
|
|
;
|
|
%ret = getelementptr inbounds {i32, [4 x ptr]}, <2 x ptr addrspace(7)> %in, i64 %idx, i32 1, i32 3
|
|
ret <2 x ptr addrspace(7)> %ret
|
|
}
|
|
|
|
define ptr addrspace(7) @simple_gep(ptr addrspace(7) %ptr, i32 %off) {
|
|
; CHECK-LABEL: define { ptr addrspace(8), i32 } @simple_gep
|
|
; CHECK-SAME: ({ ptr addrspace(8), i32 } [[PTR:%.*]], i32 [[OFF:%.*]]) #[[ATTR0]] {
|
|
; CHECK-NEXT: [[PTR_RSRC:%.*]] = extractvalue { ptr addrspace(8), i32 } [[PTR]], 0
|
|
; CHECK-NEXT: [[PTR_OFF:%.*]] = extractvalue { ptr addrspace(8), i32 } [[PTR]], 1
|
|
; CHECK-NEXT: [[TMP1:%.*]] = shl i32 [[OFF]], 2
|
|
; CHECK-NEXT: [[RET:%.*]] = add i32 [[PTR_OFF]], [[TMP1]]
|
|
; CHECK-NEXT: [[TMP2:%.*]] = insertvalue { ptr addrspace(8), i32 } poison, ptr addrspace(8) [[PTR_RSRC]], 0
|
|
; CHECK-NEXT: [[TMP3:%.*]] = insertvalue { ptr addrspace(8), i32 } [[TMP2]], i32 [[RET]], 1
|
|
; CHECK-NEXT: ret { ptr addrspace(8), i32 } [[TMP3]]
|
|
;
|
|
%ret = getelementptr i32, ptr addrspace(7) %ptr, i32 %off
|
|
ret ptr addrspace(7) %ret
|
|
}
|
|
|
|
define ptr addrspace(7) @simple_inbounds_gep(ptr addrspace(7) %ptr, i32 %off) {
|
|
; CHECK-LABEL: define { ptr addrspace(8), i32 } @simple_inbounds_gep
|
|
; CHECK-SAME: ({ ptr addrspace(8), i32 } [[PTR:%.*]], i32 [[OFF:%.*]]) #[[ATTR0]] {
|
|
; CHECK-NEXT: [[PTR_RSRC:%.*]] = extractvalue { ptr addrspace(8), i32 } [[PTR]], 0
|
|
; CHECK-NEXT: [[PTR_OFF:%.*]] = extractvalue { ptr addrspace(8), i32 } [[PTR]], 1
|
|
; CHECK-NEXT: [[TMP1:%.*]] = shl nuw nsw i32 [[OFF]], 2
|
|
; CHECK-NEXT: [[RET:%.*]] = add i32 [[PTR_OFF]], [[TMP1]]
|
|
; CHECK-NEXT: [[TMP2:%.*]] = insertvalue { ptr addrspace(8), i32 } poison, ptr addrspace(8) [[PTR_RSRC]], 0
|
|
; CHECK-NEXT: [[TMP3:%.*]] = insertvalue { ptr addrspace(8), i32 } [[TMP2]], i32 [[RET]], 1
|
|
; CHECK-NEXT: ret { ptr addrspace(8), i32 } [[TMP3]]
|
|
;
|
|
%ret = getelementptr inbounds i32, ptr addrspace(7) %ptr, i32 %off
|
|
ret ptr addrspace(7) %ret
|
|
}
|
|
|
|
define ptr addrspace(7) @zero_gep(ptr addrspace(7) %ptr) {
|
|
; CHECK-LABEL: define { ptr addrspace(8), i32 } @zero_gep
|
|
; CHECK-SAME: ({ ptr addrspace(8), i32 } [[PTR:%.*]]) #[[ATTR0]] {
|
|
; CHECK-NEXT: [[PTR_RSRC:%.*]] = extractvalue { ptr addrspace(8), i32 } [[PTR]], 0
|
|
; CHECK-NEXT: [[PTR_OFF:%.*]] = extractvalue { ptr addrspace(8), i32 } [[PTR]], 1
|
|
; CHECK-NEXT: [[TMP1:%.*]] = insertvalue { ptr addrspace(8), i32 } poison, ptr addrspace(8) [[PTR_RSRC]], 0
|
|
; CHECK-NEXT: [[RET:%.*]] = insertvalue { ptr addrspace(8), i32 } [[TMP1]], i32 [[PTR_OFF]], 1
|
|
; CHECK-NEXT: ret { ptr addrspace(8), i32 } [[RET]]
|
|
;
|
|
%ret = getelementptr i8, ptr addrspace(7) %ptr, i32 0
|
|
ret ptr addrspace(7) %ret
|
|
}
|
|
|
|
define ptr addrspace(7) @zero_gep_goes_second(ptr addrspace(7) %v0, i32 %arg) {
|
|
; CHECK-LABEL: define { ptr addrspace(8), i32 } @zero_gep_goes_second
|
|
; CHECK-SAME: ({ ptr addrspace(8), i32 } [[V0:%.*]], i32 [[ARG:%.*]]) #[[ATTR0]] {
|
|
; CHECK-NEXT: [[V0_RSRC:%.*]] = extractvalue { ptr addrspace(8), i32 } [[V0]], 0
|
|
; CHECK-NEXT: [[V0_OFF:%.*]] = extractvalue { ptr addrspace(8), i32 } [[V0]], 1
|
|
; CHECK-NEXT: [[V1:%.*]] = add i32 [[V0_OFF]], [[ARG]]
|
|
; CHECK-NEXT: [[TMP1:%.*]] = insertvalue { ptr addrspace(8), i32 } poison, ptr addrspace(8) [[V0_RSRC]], 0
|
|
; CHECK-NEXT: [[V2:%.*]] = insertvalue { ptr addrspace(8), i32 } [[TMP1]], i32 [[V1]], 1
|
|
; CHECK-NEXT: ret { ptr addrspace(8), i32 } [[V2]]
|
|
;
|
|
%v1 = getelementptr i8, ptr addrspace(7) %v0, i32 %arg
|
|
%v2 = getelementptr i8, ptr addrspace(7) %v1, i32 0
|
|
ret ptr addrspace(7) %v2
|
|
}
|
|
|
|
define ptr addrspace(7) @zero_gep_goes_first(ptr addrspace(7) %v0, i32 %arg) {
|
|
; CHECK-LABEL: define { ptr addrspace(8), i32 } @zero_gep_goes_first
|
|
; CHECK-SAME: ({ ptr addrspace(8), i32 } [[V0:%.*]], i32 [[ARG:%.*]]) #[[ATTR0]] {
|
|
; CHECK-NEXT: [[V0_RSRC:%.*]] = extractvalue { ptr addrspace(8), i32 } [[V0]], 0
|
|
; CHECK-NEXT: [[V0_OFF:%.*]] = extractvalue { ptr addrspace(8), i32 } [[V0]], 1
|
|
; CHECK-NEXT: [[V2:%.*]] = add i32 [[V0_OFF]], [[ARG]]
|
|
; CHECK-NEXT: [[TMP1:%.*]] = insertvalue { ptr addrspace(8), i32 } poison, ptr addrspace(8) [[V0_RSRC]], 0
|
|
; CHECK-NEXT: [[TMP2:%.*]] = insertvalue { ptr addrspace(8), i32 } [[TMP1]], i32 [[V2]], 1
|
|
; CHECK-NEXT: ret { ptr addrspace(8), i32 } [[TMP2]]
|
|
;
|
|
%v1 = getelementptr i8, ptr addrspace(7) %v0, i32 0
|
|
%v2 = getelementptr i8, ptr addrspace(7) %v1, i32 %arg
|
|
ret ptr addrspace(7) %v2
|
|
}
|
|
|
|
define i160 @ptrtoint(ptr addrspace(7) %ptr) {
|
|
; CHECK-LABEL: define i160 @ptrtoint
|
|
; CHECK-SAME: ({ ptr addrspace(8), i32 } [[PTR:%.*]]) #[[ATTR0]] {
|
|
; CHECK-NEXT: [[PTR_RSRC:%.*]] = extractvalue { ptr addrspace(8), i32 } [[PTR]], 0
|
|
; CHECK-NEXT: [[PTR_OFF:%.*]] = extractvalue { ptr addrspace(8), i32 } [[PTR]], 1
|
|
; CHECK-NEXT: [[RET_RSRC:%.*]] = ptrtoint ptr addrspace(8) [[PTR_RSRC]] to i160
|
|
; CHECK-NEXT: [[TMP1:%.*]] = shl nuw i160 [[RET_RSRC]], 32
|
|
; CHECK-NEXT: [[RET_OFF:%.*]] = zext i32 [[PTR_OFF]] to i160
|
|
; CHECK-NEXT: [[RET:%.*]] = or i160 [[TMP1]], [[RET_OFF]]
|
|
; CHECK-NEXT: ret i160 [[RET]]
|
|
;
|
|
%ret = ptrtoint ptr addrspace(7) %ptr to i160
|
|
ret i160 %ret
|
|
}
|
|
|
|
define <2 x i160> @ptrtoint_vec(<2 x ptr addrspace(7)> %ptr) {
|
|
; CHECK-LABEL: define <2 x i160> @ptrtoint_vec
|
|
; CHECK-SAME: ({ <2 x ptr addrspace(8)>, <2 x i32> } [[PTR:%.*]]) #[[ATTR0]] {
|
|
; CHECK-NEXT: [[PTR_RSRC:%.*]] = extractvalue { <2 x ptr addrspace(8)>, <2 x i32> } [[PTR]], 0
|
|
; CHECK-NEXT: [[PTR_OFF:%.*]] = extractvalue { <2 x ptr addrspace(8)>, <2 x i32> } [[PTR]], 1
|
|
; CHECK-NEXT: [[RET_RSRC:%.*]] = ptrtoint <2 x ptr addrspace(8)> [[PTR_RSRC]] to <2 x i160>
|
|
; CHECK-NEXT: [[TMP1:%.*]] = shl nuw <2 x i160> [[RET_RSRC]], <i160 32, i160 32>
|
|
; CHECK-NEXT: [[RET_OFF:%.*]] = zext <2 x i32> [[PTR_OFF]] to <2 x i160>
|
|
; CHECK-NEXT: [[RET:%.*]] = or <2 x i160> [[TMP1]], [[RET_OFF]]
|
|
; CHECK-NEXT: ret <2 x i160> [[RET]]
|
|
;
|
|
%ret = ptrtoint <2 x ptr addrspace(7)> %ptr to <2 x i160>
|
|
ret <2 x i160> %ret
|
|
}
|
|
|
|
define i256 @ptrtoint_long(ptr addrspace(7) %ptr) {
|
|
; CHECK-LABEL: define i256 @ptrtoint_long
|
|
; CHECK-SAME: ({ ptr addrspace(8), i32 } [[PTR:%.*]]) #[[ATTR0]] {
|
|
; CHECK-NEXT: [[PTR_RSRC:%.*]] = extractvalue { ptr addrspace(8), i32 } [[PTR]], 0
|
|
; CHECK-NEXT: [[PTR_OFF:%.*]] = extractvalue { ptr addrspace(8), i32 } [[PTR]], 1
|
|
; CHECK-NEXT: [[RET_RSRC:%.*]] = ptrtoint ptr addrspace(8) [[PTR_RSRC]] to i256
|
|
; CHECK-NEXT: [[TMP1:%.*]] = shl nuw nsw i256 [[RET_RSRC]], 32
|
|
; CHECK-NEXT: [[RET_OFF:%.*]] = zext i32 [[PTR_OFF]] to i256
|
|
; CHECK-NEXT: [[RET:%.*]] = or i256 [[TMP1]], [[RET_OFF]]
|
|
; CHECK-NEXT: ret i256 [[RET]]
|
|
;
|
|
%ret = ptrtoint ptr addrspace(7) %ptr to i256
|
|
ret i256 %ret
|
|
}
|
|
|
|
define i64 @ptrtoint_short(ptr addrspace(7) %ptr) {
|
|
; CHECK-LABEL: define i64 @ptrtoint_short
|
|
; CHECK-SAME: ({ ptr addrspace(8), i32 } [[PTR:%.*]]) #[[ATTR0]] {
|
|
; CHECK-NEXT: [[PTR_RSRC:%.*]] = extractvalue { ptr addrspace(8), i32 } [[PTR]], 0
|
|
; CHECK-NEXT: [[PTR_OFF:%.*]] = extractvalue { ptr addrspace(8), i32 } [[PTR]], 1
|
|
; CHECK-NEXT: [[RET_RSRC:%.*]] = ptrtoint ptr addrspace(8) [[PTR_RSRC]] to i64
|
|
; CHECK-NEXT: [[TMP1:%.*]] = shl i64 [[RET_RSRC]], 32
|
|
; CHECK-NEXT: [[RET_OFF:%.*]] = zext i32 [[PTR_OFF]] to i64
|
|
; CHECK-NEXT: [[RET:%.*]] = or i64 [[TMP1]], [[RET_OFF]]
|
|
; CHECK-NEXT: ret i64 [[RET]]
|
|
;
|
|
%ret = ptrtoint ptr addrspace(7) %ptr to i64
|
|
ret i64 %ret
|
|
}
|
|
|
|
define i32 @ptrtoint_offset(ptr addrspace(7) %ptr) {
|
|
; CHECK-LABEL: define i32 @ptrtoint_offset
|
|
; CHECK-SAME: ({ ptr addrspace(8), i32 } [[PTR:%.*]]) #[[ATTR0]] {
|
|
; CHECK-NEXT: [[PTR_RSRC:%.*]] = extractvalue { ptr addrspace(8), i32 } [[PTR]], 0
|
|
; CHECK-NEXT: [[PTR_OFF:%.*]] = extractvalue { ptr addrspace(8), i32 } [[PTR]], 1
|
|
; CHECK-NEXT: [[RET:%.*]] = or i32 poison, [[PTR_OFF]]
|
|
; CHECK-NEXT: ret i32 [[RET]]
|
|
;
|
|
%ret = ptrtoint ptr addrspace(7) %ptr to i32
|
|
ret i32 %ret
|
|
}
|
|
|
|
define ptr addrspace(7) @inttoptr(i160 %v) {
|
|
; CHECK-LABEL: define { ptr addrspace(8), i32 } @inttoptr
|
|
; CHECK-SAME: (i160 [[V:%.*]]) #[[ATTR0]] {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = lshr i160 [[V]], 32
|
|
; CHECK-NEXT: [[TMP2:%.*]] = trunc i160 [[TMP1]] to i128
|
|
; CHECK-NEXT: [[RET_RSRC:%.*]] = inttoptr i128 [[TMP2]] to ptr addrspace(8)
|
|
; CHECK-NEXT: [[RET_OFF:%.*]] = trunc i160 [[V]] to i32
|
|
; CHECK-NEXT: [[TMP3:%.*]] = insertvalue { ptr addrspace(8), i32 } poison, ptr addrspace(8) [[RET_RSRC]], 0
|
|
; CHECK-NEXT: [[RET:%.*]] = insertvalue { ptr addrspace(8), i32 } [[TMP3]], i32 [[RET_OFF]], 1
|
|
; CHECK-NEXT: ret { ptr addrspace(8), i32 } [[RET]]
|
|
;
|
|
%ret = inttoptr i160 %v to ptr addrspace(7)
|
|
ret ptr addrspace(7) %ret
|
|
}
|
|
|
|
define <2 x ptr addrspace(7)> @inttoptr_vec(<2 x i160> %v) {
|
|
; CHECK-LABEL: define { <2 x ptr addrspace(8)>, <2 x i32> } @inttoptr_vec
|
|
; CHECK-SAME: (<2 x i160> [[V:%.*]]) #[[ATTR0]] {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = lshr <2 x i160> [[V]], <i160 32, i160 32>
|
|
; CHECK-NEXT: [[TMP2:%.*]] = trunc <2 x i160> [[TMP1]] to <2 x i128>
|
|
; CHECK-NEXT: [[RET_RSRC:%.*]] = inttoptr <2 x i128> [[TMP2]] to <2 x ptr addrspace(8)>
|
|
; CHECK-NEXT: [[RET_OFF:%.*]] = trunc <2 x i160> [[V]] to <2 x i32>
|
|
; CHECK-NEXT: [[TMP3:%.*]] = insertvalue { <2 x ptr addrspace(8)>, <2 x i32> } poison, <2 x ptr addrspace(8)> [[RET_RSRC]], 0
|
|
; CHECK-NEXT: [[RET:%.*]] = insertvalue { <2 x ptr addrspace(8)>, <2 x i32> } [[TMP3]], <2 x i32> [[RET_OFF]], 1
|
|
; CHECK-NEXT: ret { <2 x ptr addrspace(8)>, <2 x i32> } [[RET]]
|
|
;
|
|
%ret = inttoptr <2 x i160> %v to <2 x ptr addrspace(7)>
|
|
ret <2 x ptr addrspace(7)> %ret
|
|
}
|
|
|
|
define ptr addrspace(7) @inttoptr_long(i256 %v) {
|
|
; CHECK-LABEL: define { ptr addrspace(8), i32 } @inttoptr_long
|
|
; CHECK-SAME: (i256 [[V:%.*]]) #[[ATTR0]] {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = lshr i256 [[V]], 32
|
|
; CHECK-NEXT: [[TMP2:%.*]] = trunc i256 [[TMP1]] to i128
|
|
; CHECK-NEXT: [[RET_RSRC:%.*]] = inttoptr i128 [[TMP2]] to ptr addrspace(8)
|
|
; CHECK-NEXT: [[RET_OFF:%.*]] = trunc i256 [[V]] to i32
|
|
; CHECK-NEXT: [[TMP3:%.*]] = insertvalue { ptr addrspace(8), i32 } poison, ptr addrspace(8) [[RET_RSRC]], 0
|
|
; CHECK-NEXT: [[RET:%.*]] = insertvalue { ptr addrspace(8), i32 } [[TMP3]], i32 [[RET_OFF]], 1
|
|
; CHECK-NEXT: ret { ptr addrspace(8), i32 } [[RET]]
|
|
;
|
|
%ret = inttoptr i256 %v to ptr addrspace(7)
|
|
ret ptr addrspace(7) %ret
|
|
}
|
|
|
|
define ptr addrspace(7) @inttoptr_offset(i32 %v) {
|
|
; CHECK-LABEL: define { ptr addrspace(8), i32 } @inttoptr_offset
|
|
; CHECK-SAME: (i32 [[V:%.*]]) #[[ATTR0]] {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = lshr i32 [[V]], 32
|
|
; CHECK-NEXT: [[TMP2:%.*]] = zext i32 [[TMP1]] to i128
|
|
; CHECK-NEXT: [[RET_RSRC:%.*]] = inttoptr i128 [[TMP2]] to ptr addrspace(8)
|
|
; CHECK-NEXT: [[TMP3:%.*]] = insertvalue { ptr addrspace(8), i32 } poison, ptr addrspace(8) [[RET_RSRC]], 0
|
|
; CHECK-NEXT: [[RET:%.*]] = insertvalue { ptr addrspace(8), i32 } [[TMP3]], i32 [[V]], 1
|
|
; CHECK-NEXT: ret { ptr addrspace(8), i32 } [[RET]]
|
|
;
|
|
%ret = inttoptr i32 %v to ptr addrspace(7)
|
|
ret ptr addrspace(7) %ret
|
|
}
|
|
|
|
define ptr addrspace(7) @addrspacecast(ptr addrspace(8) %buf) {
|
|
; CHECK-LABEL: define { ptr addrspace(8), i32 } @addrspacecast
|
|
; CHECK-SAME: (ptr addrspace(8) [[BUF:%.*]]) #[[ATTR0]] {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = insertvalue { ptr addrspace(8), i32 } poison, ptr addrspace(8) [[BUF]], 0
|
|
; CHECK-NEXT: [[RET:%.*]] = insertvalue { ptr addrspace(8), i32 } [[TMP1]], i32 0, 1
|
|
; CHECK-NEXT: ret { ptr addrspace(8), i32 } [[RET]]
|
|
;
|
|
%ret = addrspacecast ptr addrspace(8) %buf to ptr addrspace(7)
|
|
ret ptr addrspace(7) %ret
|
|
}
|
|
|
|
define <2 x ptr addrspace(7)> @addrspacecast_vec(<2 x ptr addrspace(8)> %buf) {
|
|
; CHECK-LABEL: define { <2 x ptr addrspace(8)>, <2 x i32> } @addrspacecast_vec
|
|
; CHECK-SAME: (<2 x ptr addrspace(8)> [[BUF:%.*]]) #[[ATTR0]] {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = insertvalue { <2 x ptr addrspace(8)>, <2 x i32> } poison, <2 x ptr addrspace(8)> [[BUF]], 0
|
|
; CHECK-NEXT: [[RET:%.*]] = insertvalue { <2 x ptr addrspace(8)>, <2 x i32> } [[TMP1]], <2 x i32> zeroinitializer, 1
|
|
; CHECK-NEXT: ret { <2 x ptr addrspace(8)>, <2 x i32> } [[RET]]
|
|
;
|
|
%ret = addrspacecast <2 x ptr addrspace(8)> %buf to <2 x ptr addrspace(7)>
|
|
ret <2 x ptr addrspace(7)> %ret
|
|
}
|
|
|
|
define i1 @icmp_eq(ptr addrspace(7) %a, ptr addrspace(7) %b) {
|
|
; CHECK-LABEL: define i1 @icmp_eq
|
|
; CHECK-SAME: ({ ptr addrspace(8), i32 } [[A:%.*]], { ptr addrspace(8), i32 } [[B:%.*]]) #[[ATTR0]] {
|
|
; CHECK-NEXT: [[B_RSRC:%.*]] = extractvalue { ptr addrspace(8), i32 } [[B]], 0
|
|
; CHECK-NEXT: [[B_OFF:%.*]] = extractvalue { ptr addrspace(8), i32 } [[B]], 1
|
|
; CHECK-NEXT: [[A_RSRC:%.*]] = extractvalue { ptr addrspace(8), i32 } [[A]], 0
|
|
; CHECK-NEXT: [[A_OFF:%.*]] = extractvalue { ptr addrspace(8), i32 } [[A]], 1
|
|
; CHECK-NEXT: [[RET_RSRC:%.*]] = icmp eq ptr addrspace(8) [[A_RSRC]], [[B_RSRC]]
|
|
; CHECK-NEXT: [[RET_OFF:%.*]] = icmp eq i32 [[A_OFF]], [[B_OFF]]
|
|
; CHECK-NEXT: [[RET:%.*]] = and i1 [[RET_RSRC]], [[RET_OFF]]
|
|
; CHECK-NEXT: ret i1 [[RET]]
|
|
;
|
|
%ret = icmp eq ptr addrspace(7) %a, %b
|
|
ret i1 %ret
|
|
}
|
|
|
|
define i1 @icmp_ne(ptr addrspace(7) %a, ptr addrspace(7) %b) {
|
|
; CHECK-LABEL: define i1 @icmp_ne
|
|
; CHECK-SAME: ({ ptr addrspace(8), i32 } [[A:%.*]], { ptr addrspace(8), i32 } [[B:%.*]]) #[[ATTR0]] {
|
|
; CHECK-NEXT: [[B_RSRC:%.*]] = extractvalue { ptr addrspace(8), i32 } [[B]], 0
|
|
; CHECK-NEXT: [[B_OFF:%.*]] = extractvalue { ptr addrspace(8), i32 } [[B]], 1
|
|
; CHECK-NEXT: [[A_RSRC:%.*]] = extractvalue { ptr addrspace(8), i32 } [[A]], 0
|
|
; CHECK-NEXT: [[A_OFF:%.*]] = extractvalue { ptr addrspace(8), i32 } [[A]], 1
|
|
; CHECK-NEXT: [[RET_RSRC:%.*]] = icmp ne ptr addrspace(8) [[A_RSRC]], [[B_RSRC]]
|
|
; CHECK-NEXT: [[RET_OFF:%.*]] = icmp ne i32 [[A_OFF]], [[B_OFF]]
|
|
; CHECK-NEXT: [[RET:%.*]] = or i1 [[RET_RSRC]], [[RET_OFF]]
|
|
; CHECK-NEXT: ret i1 [[RET]]
|
|
;
|
|
%ret = icmp ne ptr addrspace(7) %a, %b
|
|
ret i1 %ret
|
|
}
|
|
|
|
define <2 x i1> @icmp_eq_vec(<2 x ptr addrspace(7)> %a, <2 x ptr addrspace(7)> %b) {
|
|
; CHECK-LABEL: define <2 x i1> @icmp_eq_vec
|
|
; CHECK-SAME: ({ <2 x ptr addrspace(8)>, <2 x i32> } [[A:%.*]], { <2 x ptr addrspace(8)>, <2 x i32> } [[B:%.*]]) #[[ATTR0]] {
|
|
; CHECK-NEXT: [[B_RSRC:%.*]] = extractvalue { <2 x ptr addrspace(8)>, <2 x i32> } [[B]], 0
|
|
; CHECK-NEXT: [[B_OFF:%.*]] = extractvalue { <2 x ptr addrspace(8)>, <2 x i32> } [[B]], 1
|
|
; CHECK-NEXT: [[A_RSRC:%.*]] = extractvalue { <2 x ptr addrspace(8)>, <2 x i32> } [[A]], 0
|
|
; CHECK-NEXT: [[A_OFF:%.*]] = extractvalue { <2 x ptr addrspace(8)>, <2 x i32> } [[A]], 1
|
|
; CHECK-NEXT: [[RET_RSRC:%.*]] = icmp eq <2 x ptr addrspace(8)> [[A_RSRC]], [[B_RSRC]]
|
|
; CHECK-NEXT: [[RET_OFF:%.*]] = icmp eq <2 x i32> [[A_OFF]], [[B_OFF]]
|
|
; CHECK-NEXT: [[RET:%.*]] = and <2 x i1> [[RET_RSRC]], [[RET_OFF]]
|
|
; CHECK-NEXT: ret <2 x i1> [[RET]]
|
|
;
|
|
%ret = icmp eq <2 x ptr addrspace(7)> %a, %b
|
|
ret <2 x i1> %ret
|
|
}
|
|
|
|
define <2 x i1> @icmp_ne_vec(<2 x ptr addrspace(7)> %a, <2 x ptr addrspace(7)> %b) {
|
|
; CHECK-LABEL: define <2 x i1> @icmp_ne_vec
|
|
; CHECK-SAME: ({ <2 x ptr addrspace(8)>, <2 x i32> } [[A:%.*]], { <2 x ptr addrspace(8)>, <2 x i32> } [[B:%.*]]) #[[ATTR0]] {
|
|
; CHECK-NEXT: [[B_RSRC:%.*]] = extractvalue { <2 x ptr addrspace(8)>, <2 x i32> } [[B]], 0
|
|
; CHECK-NEXT: [[B_OFF:%.*]] = extractvalue { <2 x ptr addrspace(8)>, <2 x i32> } [[B]], 1
|
|
; CHECK-NEXT: [[A_RSRC:%.*]] = extractvalue { <2 x ptr addrspace(8)>, <2 x i32> } [[A]], 0
|
|
; CHECK-NEXT: [[A_OFF:%.*]] = extractvalue { <2 x ptr addrspace(8)>, <2 x i32> } [[A]], 1
|
|
; CHECK-NEXT: [[RET_RSRC:%.*]] = icmp ne <2 x ptr addrspace(8)> [[A_RSRC]], [[B_RSRC]]
|
|
; CHECK-NEXT: [[RET_OFF:%.*]] = icmp ne <2 x i32> [[A_OFF]], [[B_OFF]]
|
|
; CHECK-NEXT: [[RET:%.*]] = or <2 x i1> [[RET_RSRC]], [[RET_OFF]]
|
|
; CHECK-NEXT: ret <2 x i1> [[RET]]
|
|
;
|
|
%ret = icmp ne <2 x ptr addrspace(7)> %a, %b
|
|
ret <2 x i1> %ret
|
|
}
|
|
|
|
define ptr addrspace(7) @freeze(ptr addrspace(7) %p) {
|
|
; CHECK-LABEL: define { ptr addrspace(8), i32 } @freeze
|
|
; CHECK-SAME: ({ ptr addrspace(8), i32 } [[P:%.*]]) #[[ATTR0]] {
|
|
; CHECK-NEXT: [[P_RSRC:%.*]] = extractvalue { ptr addrspace(8), i32 } [[P]], 0
|
|
; CHECK-NEXT: [[P_OFF:%.*]] = extractvalue { ptr addrspace(8), i32 } [[P]], 1
|
|
; CHECK-NEXT: [[RET_RSRC:%.*]] = freeze ptr addrspace(8) [[P_RSRC]]
|
|
; CHECK-NEXT: [[RET_OFF:%.*]] = freeze i32 [[P_OFF]]
|
|
; CHECK-NEXT: [[TMP1:%.*]] = insertvalue { ptr addrspace(8), i32 } poison, ptr addrspace(8) [[RET_RSRC]], 0
|
|
; CHECK-NEXT: [[RET:%.*]] = insertvalue { ptr addrspace(8), i32 } [[TMP1]], i32 [[RET_OFF]], 1
|
|
; CHECK-NEXT: ret { ptr addrspace(8), i32 } [[RET]]
|
|
;
|
|
%ret = freeze ptr addrspace(7) %p
|
|
ret ptr addrspace(7) %ret
|
|
}
|
|
|
|
define <2 x ptr addrspace(7)> @freeze_vec(<2 x ptr addrspace(7)> %p) {
|
|
; CHECK-LABEL: define { <2 x ptr addrspace(8)>, <2 x i32> } @freeze_vec
|
|
; CHECK-SAME: ({ <2 x ptr addrspace(8)>, <2 x i32> } [[P:%.*]]) #[[ATTR0]] {
|
|
; CHECK-NEXT: [[P_RSRC:%.*]] = extractvalue { <2 x ptr addrspace(8)>, <2 x i32> } [[P]], 0
|
|
; CHECK-NEXT: [[P_OFF:%.*]] = extractvalue { <2 x ptr addrspace(8)>, <2 x i32> } [[P]], 1
|
|
; CHECK-NEXT: [[RET_RSRC:%.*]] = freeze <2 x ptr addrspace(8)> [[P_RSRC]]
|
|
; CHECK-NEXT: [[RET_OFF:%.*]] = freeze <2 x i32> [[P_OFF]]
|
|
; CHECK-NEXT: [[TMP1:%.*]] = insertvalue { <2 x ptr addrspace(8)>, <2 x i32> } poison, <2 x ptr addrspace(8)> [[RET_RSRC]], 0
|
|
; CHECK-NEXT: [[RET:%.*]] = insertvalue { <2 x ptr addrspace(8)>, <2 x i32> } [[TMP1]], <2 x i32> [[RET_OFF]], 1
|
|
; CHECK-NEXT: ret { <2 x ptr addrspace(8)>, <2 x i32> } [[RET]]
|
|
;
|
|
%ret = freeze <2 x ptr addrspace(7)> %p
|
|
ret <2 x ptr addrspace(7)> %ret
|
|
}
|
|
|
|
define ptr addrspace(7) @extractelement(<2 x ptr addrspace(7)> %v, i32 %i) {
|
|
; CHECK-LABEL: define { ptr addrspace(8), i32 } @extractelement
|
|
; CHECK-SAME: ({ <2 x ptr addrspace(8)>, <2 x i32> } [[V:%.*]], i32 [[I:%.*]]) #[[ATTR0]] {
|
|
; CHECK-NEXT: [[V_RSRC:%.*]] = extractvalue { <2 x ptr addrspace(8)>, <2 x i32> } [[V]], 0
|
|
; CHECK-NEXT: [[V_OFF:%.*]] = extractvalue { <2 x ptr addrspace(8)>, <2 x i32> } [[V]], 1
|
|
; CHECK-NEXT: [[RET_RSRC:%.*]] = extractelement <2 x ptr addrspace(8)> [[V_RSRC]], i32 [[I]]
|
|
; CHECK-NEXT: [[RET_OFF:%.*]] = extractelement <2 x i32> [[V_OFF]], i32 [[I]]
|
|
; CHECK-NEXT: [[TMP1:%.*]] = insertvalue { ptr addrspace(8), i32 } poison, ptr addrspace(8) [[RET_RSRC]], 0
|
|
; CHECK-NEXT: [[RET:%.*]] = insertvalue { ptr addrspace(8), i32 } [[TMP1]], i32 [[RET_OFF]], 1
|
|
; CHECK-NEXT: ret { ptr addrspace(8), i32 } [[RET]]
|
|
;
|
|
%ret = extractelement <2 x ptr addrspace(7)> %v, i32 %i
|
|
ret ptr addrspace(7) %ret
|
|
}
|
|
|
|
define <2 x ptr addrspace(7)> @insertelement(<2 x ptr addrspace(7)> %v, ptr addrspace(7) %s, i32 %i) {
|
|
; CHECK-LABEL: define { <2 x ptr addrspace(8)>, <2 x i32> } @insertelement
|
|
; CHECK-SAME: ({ <2 x ptr addrspace(8)>, <2 x i32> } [[V:%.*]], { ptr addrspace(8), i32 } [[S:%.*]], i32 [[I:%.*]]) #[[ATTR0]] {
|
|
; CHECK-NEXT: [[S_RSRC:%.*]] = extractvalue { ptr addrspace(8), i32 } [[S]], 0
|
|
; CHECK-NEXT: [[S_OFF:%.*]] = extractvalue { ptr addrspace(8), i32 } [[S]], 1
|
|
; CHECK-NEXT: [[V_RSRC:%.*]] = extractvalue { <2 x ptr addrspace(8)>, <2 x i32> } [[V]], 0
|
|
; CHECK-NEXT: [[V_OFF:%.*]] = extractvalue { <2 x ptr addrspace(8)>, <2 x i32> } [[V]], 1
|
|
; CHECK-NEXT: [[RET_RSRC:%.*]] = insertelement <2 x ptr addrspace(8)> [[V_RSRC]], ptr addrspace(8) [[S_RSRC]], i32 [[I]]
|
|
; CHECK-NEXT: [[RET_OFF:%.*]] = insertelement <2 x i32> [[V_OFF]], i32 [[S_OFF]], i32 [[I]]
|
|
; CHECK-NEXT: [[TMP1:%.*]] = insertvalue { <2 x ptr addrspace(8)>, <2 x i32> } poison, <2 x ptr addrspace(8)> [[RET_RSRC]], 0
|
|
; CHECK-NEXT: [[RET:%.*]] = insertvalue { <2 x ptr addrspace(8)>, <2 x i32> } [[TMP1]], <2 x i32> [[RET_OFF]], 1
|
|
; CHECK-NEXT: ret { <2 x ptr addrspace(8)>, <2 x i32> } [[RET]]
|
|
;
|
|
%ret = insertelement <2 x ptr addrspace(7)> %v, ptr addrspace(7) %s, i32 %i
|
|
ret <2 x ptr addrspace(7)> %ret
|
|
}
|
|
|
|
define <4 x ptr addrspace(7)> @shufflenvector(<2 x ptr addrspace(7)> %a, <2 x ptr addrspace(7)> %b) {
|
|
; CHECK-LABEL: define { <4 x ptr addrspace(8)>, <4 x i32> } @shufflenvector
|
|
; CHECK-SAME: ({ <2 x ptr addrspace(8)>, <2 x i32> } [[A:%.*]], { <2 x ptr addrspace(8)>, <2 x i32> } [[B:%.*]]) #[[ATTR0]] {
|
|
; CHECK-NEXT: [[B_RSRC:%.*]] = extractvalue { <2 x ptr addrspace(8)>, <2 x i32> } [[B]], 0
|
|
; CHECK-NEXT: [[B_OFF:%.*]] = extractvalue { <2 x ptr addrspace(8)>, <2 x i32> } [[B]], 1
|
|
; CHECK-NEXT: [[A_RSRC:%.*]] = extractvalue { <2 x ptr addrspace(8)>, <2 x i32> } [[A]], 0
|
|
; CHECK-NEXT: [[A_OFF:%.*]] = extractvalue { <2 x ptr addrspace(8)>, <2 x i32> } [[A]], 1
|
|
; CHECK-NEXT: [[RET_RSRC:%.*]] = shufflevector <2 x ptr addrspace(8)> [[A_RSRC]], <2 x ptr addrspace(8)> [[B_RSRC]], <4 x i32> <i32 0, i32 3, i32 1, i32 2>
|
|
; CHECK-NEXT: [[RET_OFF:%.*]] = shufflevector <2 x i32> [[A_OFF]], <2 x i32> [[B_OFF]], <4 x i32> <i32 0, i32 3, i32 1, i32 2>
|
|
; CHECK-NEXT: [[TMP1:%.*]] = insertvalue { <4 x ptr addrspace(8)>, <4 x i32> } poison, <4 x ptr addrspace(8)> [[RET_RSRC]], 0
|
|
; CHECK-NEXT: [[RET:%.*]] = insertvalue { <4 x ptr addrspace(8)>, <4 x i32> } [[TMP1]], <4 x i32> [[RET_OFF]], 1
|
|
; CHECK-NEXT: ret { <4 x ptr addrspace(8)>, <4 x i32> } [[RET]]
|
|
;
|
|
%ret = shufflevector <2 x ptr addrspace(7)> %a, <2 x ptr addrspace(7)> %b, <4 x i32> <i32 0, i32 3, i32 1, i32 2>
|
|
ret <4 x ptr addrspace(7)> %ret
|
|
}
|
|
|
|
declare ptr addrspace(7) @llvm.ptrmask.p7.i32(ptr addrspace(7), i32)
|
|
|
|
define ptr addrspace(7) @ptrmask(ptr addrspace(7) %p, i32 %mask) {
|
|
; CHECK-LABEL: define { ptr addrspace(8), i32 } @ptrmask
|
|
; CHECK-SAME: ({ ptr addrspace(8), i32 } [[P:%.*]], i32 [[MASK:%.*]]) #[[ATTR0]] {
|
|
; CHECK-NEXT: [[P_RSRC:%.*]] = extractvalue { ptr addrspace(8), i32 } [[P]], 0
|
|
; CHECK-NEXT: [[P_OFF:%.*]] = extractvalue { ptr addrspace(8), i32 } [[P]], 1
|
|
; CHECK-NEXT: [[RET_OFF:%.*]] = and i32 [[P_OFF]], [[MASK]]
|
|
; CHECK-NEXT: [[TMP1:%.*]] = insertvalue { ptr addrspace(8), i32 } poison, ptr addrspace(8) [[P_RSRC]], 0
|
|
; CHECK-NEXT: [[RET:%.*]] = insertvalue { ptr addrspace(8), i32 } [[TMP1]], i32 [[RET_OFF]], 1
|
|
; CHECK-NEXT: ret { ptr addrspace(8), i32 } [[RET]]
|
|
;
|
|
%ret = call ptr addrspace(7) @llvm.ptrmask.p7.i32(ptr addrspace(7) %p, i32 %mask)
|
|
ret ptr addrspace(7) %ret
|
|
}
|
|
|
|
declare ptr @llvm.invariant.start.p7(i64, ptr addrspace(7) nocapture)
|
|
declare void @llvm.invariant.end.p7(ptr, i64, ptr addrspace(7) nocapture)
|
|
|
|
define i32 @invariant_start_end(ptr addrspace(7) %p) {
|
|
; CHECK-LABEL: define i32 @invariant_start_end
|
|
; CHECK-SAME: ({ ptr addrspace(8), i32 } [[P:%.*]]) #[[ATTR0]] {
|
|
; CHECK-NEXT: [[P_RSRC:%.*]] = extractvalue { ptr addrspace(8), i32 } [[P]], 0
|
|
; CHECK-NEXT: [[P_OFF:%.*]] = extractvalue { ptr addrspace(8), i32 } [[P]], 1
|
|
; CHECK-NEXT: [[INV:%.*]] = call ptr @llvm.invariant.start.p8(i64 256, ptr addrspace(8) [[P_RSRC]])
|
|
; CHECK-NEXT: [[V:%.*]] = call i32 @llvm.amdgcn.raw.ptr.buffer.load.i32(ptr addrspace(8) align 4 [[P_RSRC]], i32 [[P_OFF]], i32 0, i32 0)
|
|
; CHECK-NEXT: call void @llvm.invariant.end.p8(ptr [[INV]], i64 256, ptr addrspace(8) [[P_RSRC]])
|
|
; CHECK-NEXT: ret i32 [[V]]
|
|
;
|
|
%inv = call ptr @llvm.invariant.start.p7(i64 256, ptr addrspace(7) %p)
|
|
%v = load i32, ptr addrspace(7) %p
|
|
call void @llvm.invariant.end.p7(ptr %inv, i64 256, ptr addrspace(7) %p)
|
|
ret i32 %v
|
|
}
|
|
|
|
declare ptr addrspace(7) @llvm.launder.invariant.group.p7(ptr addrspace(7) nocapture)
|
|
declare ptr addrspace(7) @llvm.strip.invariant.group.p7(ptr addrspace(7) nocapture)
|
|
|
|
define ptr addrspace(7) @invariant_group(ptr addrspace(7) %p) {
|
|
; CHECK-LABEL: define { ptr addrspace(8), i32 } @invariant_group
|
|
; CHECK-SAME: ({ ptr addrspace(8), i32 } [[P:%.*]]) #[[ATTR0]] {
|
|
; CHECK-NEXT: [[P_RSRC:%.*]] = extractvalue { ptr addrspace(8), i32 } [[P]], 0
|
|
; CHECK-NEXT: [[P_OFF:%.*]] = extractvalue { ptr addrspace(8), i32 } [[P]], 1
|
|
; CHECK-NEXT: [[LAUNDERED:%.*]] = call ptr addrspace(8) @llvm.launder.invariant.group.p8(ptr addrspace(8) [[P_RSRC]])
|
|
; CHECK-NEXT: [[STRIPPED:%.*]] = call ptr addrspace(8) @llvm.strip.invariant.group.p8(ptr addrspace(8) [[LAUNDERED]])
|
|
; CHECK-NEXT: [[TMP1:%.*]] = insertvalue { ptr addrspace(8), i32 } poison, ptr addrspace(8) [[STRIPPED]], 0
|
|
; CHECK-NEXT: [[TMP2:%.*]] = insertvalue { ptr addrspace(8), i32 } [[TMP1]], i32 [[P_OFF]], 1
|
|
; CHECK-NEXT: ret { ptr addrspace(8), i32 } [[TMP2]]
|
|
;
|
|
%laundered = call ptr addrspace(7) @llvm.launder.invariant.group.p7(ptr addrspace(7) %p)
|
|
%stripped = call ptr addrspace(7) @llvm.strip.invariant.group.p7(ptr addrspace(7) %laundered)
|
|
ret ptr addrspace(7) %stripped
|
|
}
|