Files
TheRock/compiler/amd-llvm/llvm/test/Transforms/InstCombine/AMDGPU/llvm.amdgcn.readfirstlane.ll
T
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

676 lines
22 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
; RUN: opt -mtriple=amdgcn-- -mcpu=gfx1030 -passes=instcombine -S < %s | FileCheck %s
; test unary
define float @hoist_fneg_f32(float %arg) {
; CHECK-LABEL: define float @hoist_fneg_f32(
; CHECK-SAME: float [[ARG:%.*]]) #[[ATTR0:[0-9]+]] {
; CHECK-NEXT: [[BB:.*:]]
; CHECK-NEXT: [[TMP0:%.*]] = call float @llvm.amdgcn.readfirstlane.f32(float [[ARG]])
; CHECK-NEXT: [[RFL:%.*]] = fneg float [[TMP0]]
; CHECK-NEXT: ret float [[RFL]]
;
bb:
%val = fneg float %arg
%rfl = call float @llvm.amdgcn.readfirstlane.f32(float %val)
ret float %rfl
}
define double @hoist_fneg_f64(double %arg) {
; CHECK-LABEL: define double @hoist_fneg_f64(
; CHECK-SAME: double [[ARG:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[BB:.*:]]
; CHECK-NEXT: [[TMP0:%.*]] = call double @llvm.amdgcn.readfirstlane.f64(double [[ARG]])
; CHECK-NEXT: [[RFL:%.*]] = fneg double [[TMP0]]
; CHECK-NEXT: ret double [[RFL]]
;
bb:
%val = fneg double %arg
%rfl = call double @llvm.amdgcn.readfirstlane.f64(double %val)
ret double %rfl
}
; test casts
define i32 @hoist_trunc(i64 %arg) {
; CHECK-LABEL: define i32 @hoist_trunc(
; CHECK-SAME: i64 [[ARG:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[BB:.*:]]
; CHECK-NEXT: [[RFL:%.*]] = call i64 @llvm.amdgcn.readfirstlane.i64(i64 [[ARG]])
; CHECK-NEXT: [[TMP0:%.*]] = trunc i64 [[RFL]] to i32
; CHECK-NEXT: ret i32 [[TMP0]]
;
bb:
%val = trunc i64 %arg to i32
%rfl = call i32 @llvm.amdgcn.readfirstlane.i32(i32 %val)
ret i32 %rfl
}
define i64 @hoist_zext(i32 %arg) {
; CHECK-LABEL: define i64 @hoist_zext(
; CHECK-SAME: i32 [[ARG:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[BB:.*:]]
; CHECK-NEXT: [[RFL:%.*]] = call i32 @llvm.amdgcn.readfirstlane.i32(i32 [[ARG]])
; CHECK-NEXT: [[TMP0:%.*]] = zext i32 [[RFL]] to i64
; CHECK-NEXT: ret i64 [[TMP0]]
;
bb:
%val = zext i32 %arg to i64
%rfl = call i64 @llvm.amdgcn.readfirstlane.i64(i64 %val)
ret i64 %rfl
}
define i64 @hoist_sext(i32 %arg) {
; CHECK-LABEL: define i64 @hoist_sext(
; CHECK-SAME: i32 [[ARG:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[BB:.*:]]
; CHECK-NEXT: [[RFL:%.*]] = call i32 @llvm.amdgcn.readfirstlane.i32(i32 [[ARG]])
; CHECK-NEXT: [[TMP0:%.*]] = zext i32 [[RFL]] to i64
; CHECK-NEXT: ret i64 [[TMP0]]
;
bb:
%val = zext i32 %arg to i64
%rfl = call i64 @llvm.amdgcn.readfirstlane.i64(i64 %val)
ret i64 %rfl
}
define i32 @hoist_fptoui(float %arg) {
; CHECK-LABEL: define i32 @hoist_fptoui(
; CHECK-SAME: float [[ARG:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[BB:.*:]]
; CHECK-NEXT: [[RFL:%.*]] = call float @llvm.amdgcn.readfirstlane.f32(float [[ARG]])
; CHECK-NEXT: [[TMP0:%.*]] = fptoui float [[RFL]] to i32
; CHECK-NEXT: ret i32 [[TMP0]]
;
bb:
%val = fptoui float %arg to i32
%rfl = call i32 @llvm.amdgcn.readfirstlane.i32(i32 %val)
ret i32 %rfl
}
define i32 @hoist_fptosi(float %arg) {
; CHECK-LABEL: define i32 @hoist_fptosi(
; CHECK-SAME: float [[ARG:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[BB:.*:]]
; CHECK-NEXT: [[RFL:%.*]] = call float @llvm.amdgcn.readfirstlane.f32(float [[ARG]])
; CHECK-NEXT: [[TMP0:%.*]] = fptosi float [[RFL]] to i32
; CHECK-NEXT: ret i32 [[TMP0]]
;
bb:
%val = fptosi float %arg to i32
%rfl = call i32 @llvm.amdgcn.readfirstlane.i32(i32 %val)
ret i32 %rfl
}
define float @hoist_uitofp(i32 %arg) {
; CHECK-LABEL: define float @hoist_uitofp(
; CHECK-SAME: i32 [[ARG:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[BB:.*:]]
; CHECK-NEXT: [[RFL:%.*]] = call i32 @llvm.amdgcn.readfirstlane.i32(i32 [[ARG]])
; CHECK-NEXT: [[TMP0:%.*]] = uitofp i32 [[RFL]] to float
; CHECK-NEXT: ret float [[TMP0]]
;
bb:
%val = uitofp i32 %arg to float
%rfl = call float @llvm.amdgcn.readfirstlane.f32(float %val)
ret float %rfl
}
define float @hoist_sitofp(i32 %arg) {
; CHECK-LABEL: define float @hoist_sitofp(
; CHECK-SAME: i32 [[ARG:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[BB:.*:]]
; CHECK-NEXT: [[RFL:%.*]] = call i32 @llvm.amdgcn.readfirstlane.i32(i32 [[ARG]])
; CHECK-NEXT: [[TMP0:%.*]] = sitofp i32 [[RFL]] to float
; CHECK-NEXT: ret float [[TMP0]]
;
bb:
%val = sitofp i32 %arg to float
%rfl = call float @llvm.amdgcn.readfirstlane.f32(float %val)
ret float %rfl
}
define float @hoist_fptrunc(double %arg) {
; CHECK-LABEL: define float @hoist_fptrunc(
; CHECK-SAME: double [[ARG:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[BB:.*:]]
; CHECK-NEXT: [[RFL:%.*]] = call double @llvm.amdgcn.readfirstlane.f64(double [[ARG]])
; CHECK-NEXT: [[TMP0:%.*]] = fptrunc double [[RFL]] to float
; CHECK-NEXT: ret float [[TMP0]]
;
bb:
%val = fptrunc double %arg to float
%rfl = call float @llvm.amdgcn.readfirstlane.f32(float %val)
ret float %rfl
}
define float @hoist_fpext(half %arg) {
; CHECK-LABEL: define float @hoist_fpext(
; CHECK-SAME: half [[ARG:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[BB:.*:]]
; CHECK-NEXT: [[RFL:%.*]] = call half @llvm.amdgcn.readfirstlane.f16(half [[ARG]])
; CHECK-NEXT: [[TMP0:%.*]] = fpext half [[RFL]] to float
; CHECK-NEXT: ret float [[TMP0]]
;
bb:
%val = fpext half %arg to float
%rfl = call float @llvm.amdgcn.readfirstlane.f32(float %val)
ret float %rfl
}
define i64 @hoist_ptrtoint(ptr %arg) {
; CHECK-LABEL: define i64 @hoist_ptrtoint(
; CHECK-SAME: ptr [[ARG:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[BB:.*:]]
; CHECK-NEXT: [[RFL:%.*]] = call ptr @llvm.amdgcn.readfirstlane.p0(ptr [[ARG]])
; CHECK-NEXT: [[TMP0:%.*]] = ptrtoint ptr [[RFL]] to i64
; CHECK-NEXT: ret i64 [[TMP0]]
;
bb:
%val = ptrtoint ptr %arg to i64
%rfl = call i64 @llvm.amdgcn.readfirstlane.i64(i64 %val)
ret i64 %rfl
}
define ptr @hoist_inttoptr(i64 %arg) {
; CHECK-LABEL: define ptr @hoist_inttoptr(
; CHECK-SAME: i64 [[ARG:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[BB:.*:]]
; CHECK-NEXT: [[RFL:%.*]] = call i64 @llvm.amdgcn.readfirstlane.i64(i64 [[ARG]])
; CHECK-NEXT: [[TMP0:%.*]] = inttoptr i64 [[RFL]] to ptr
; CHECK-NEXT: ret ptr [[TMP0]]
;
bb:
%val = inttoptr i64 %arg to ptr
%rfl = call ptr @llvm.amdgcn.readfirstlane.p0(ptr %val)
ret ptr %rfl
}
define float @hoist_bitcast(i32 %arg) {
; CHECK-LABEL: define float @hoist_bitcast(
; CHECK-SAME: i32 [[ARG:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[BB:.*:]]
; CHECK-NEXT: [[RFL:%.*]] = call i32 @llvm.amdgcn.readfirstlane.i32(i32 [[ARG]])
; CHECK-NEXT: [[TMP0:%.*]] = bitcast i32 [[RFL]] to float
; CHECK-NEXT: ret float [[TMP0]]
;
bb:
%val = bitcast i32 %arg to float
%rfl = call float @llvm.amdgcn.readfirstlane.f32(float %val)
ret float %rfl
}
define ptr addrspace(1) @hoist_addrspacecast(ptr addrspace(0) %arg) {
; CHECK-LABEL: define ptr addrspace(1) @hoist_addrspacecast(
; CHECK-SAME: ptr [[ARG:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[BB:.*:]]
; CHECK-NEXT: [[RFL:%.*]] = call ptr @llvm.amdgcn.readfirstlane.p0(ptr [[ARG]])
; CHECK-NEXT: [[TMP0:%.*]] = addrspacecast ptr [[RFL]] to ptr addrspace(1)
; CHECK-NEXT: ret ptr addrspace(1) [[TMP0]]
;
bb:
%val = addrspacecast ptr addrspace(0) %arg to ptr addrspace(1)
%rfl = call ptr addrspace(1) @llvm.amdgcn.readfirstlane.p1(ptr addrspace(1) %val)
ret ptr addrspace(1) %rfl
}
; test binary i32
define i32 @hoist_add_i32(i32 %arg) {
; CHECK-LABEL: define i32 @hoist_add_i32(
; CHECK-SAME: i32 [[ARG:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[BB:.*:]]
; CHECK-NEXT: [[TMP0:%.*]] = call i32 @llvm.amdgcn.readfirstlane.i32(i32 [[ARG]])
; CHECK-NEXT: [[RFL:%.*]] = add i32 [[TMP0]], 16777215
; CHECK-NEXT: ret i32 [[RFL]]
;
bb:
%val = add i32 %arg, 16777215
%rfl = call i32 @llvm.amdgcn.readfirstlane.i32(i32 %val)
ret i32 %rfl
}
define float @hoist_fadd_f32(float %arg) {
; CHECK-LABEL: define float @hoist_fadd_f32(
; CHECK-SAME: float [[ARG:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[BB:.*:]]
; CHECK-NEXT: [[TMP0:%.*]] = call float @llvm.amdgcn.readfirstlane.f32(float [[ARG]])
; CHECK-NEXT: [[RFL:%.*]] = fadd float [[TMP0]], 1.280000e+02
; CHECK-NEXT: ret float [[RFL]]
;
bb:
%val = fadd float %arg, 128.0
%rfl = call float @llvm.amdgcn.readfirstlane.f32(float %val)
ret float %rfl
}
define i32 @hoist_sub_i32(i32 %arg) {
; CHECK-LABEL: define i32 @hoist_sub_i32(
; CHECK-SAME: i32 [[ARG:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[BB:.*:]]
; CHECK-NEXT: [[TMP0:%.*]] = call i32 @llvm.amdgcn.readfirstlane.i32(i32 [[ARG]])
; CHECK-NEXT: [[RFL:%.*]] = add i32 [[TMP0]], -16777215
; CHECK-NEXT: ret i32 [[RFL]]
;
bb:
%val = sub i32 %arg, 16777215
%rfl = call i32 @llvm.amdgcn.readfirstlane.i32(i32 %val)
ret i32 %rfl
}
define float @hoist_fsub_f32(float %arg) {
; CHECK-LABEL: define float @hoist_fsub_f32(
; CHECK-SAME: float [[ARG:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[BB:.*:]]
; CHECK-NEXT: [[TMP0:%.*]] = call float @llvm.amdgcn.readfirstlane.f32(float [[ARG]])
; CHECK-NEXT: [[RFL:%.*]] = fadd float [[TMP0]], -1.280000e+02
; CHECK-NEXT: ret float [[RFL]]
;
bb:
%val = fsub float %arg, 128.0
%rfl = call float @llvm.amdgcn.readfirstlane.f32(float %val)
ret float %rfl
}
define i32 @hoist_mul_i32(i32 %arg) {
; CHECK-LABEL: define i32 @hoist_mul_i32(
; CHECK-SAME: i32 [[ARG:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[BB:.*:]]
; CHECK-NEXT: [[TMP0:%.*]] = call i32 @llvm.amdgcn.readfirstlane.i32(i32 [[ARG]])
; CHECK-NEXT: [[RFL:%.*]] = mul i32 [[TMP0]], 16777215
; CHECK-NEXT: ret i32 [[RFL]]
;
bb:
%val = mul i32 %arg, 16777215
%rfl = call i32 @llvm.amdgcn.readfirstlane.i32(i32 %val)
ret i32 %rfl
}
define float @hoist_fmul_f32(float %arg) {
; CHECK-LABEL: define float @hoist_fmul_f32(
; CHECK-SAME: float [[ARG:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[BB:.*:]]
; CHECK-NEXT: [[TMP0:%.*]] = call float @llvm.amdgcn.readfirstlane.f32(float [[ARG]])
; CHECK-NEXT: [[RFL:%.*]] = fmul float [[TMP0]], 1.280000e+02
; CHECK-NEXT: ret float [[RFL]]
;
bb:
%val = fmul float %arg, 128.0
%rfl = call float @llvm.amdgcn.readfirstlane.f32(float %val)
ret float %rfl
}
define i32 @hoist_udiv_i32(i32 %arg) {
; CHECK-LABEL: define i32 @hoist_udiv_i32(
; CHECK-SAME: i32 [[ARG:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[BB:.*:]]
; CHECK-NEXT: [[TMP0:%.*]] = call i32 @llvm.amdgcn.readfirstlane.i32(i32 [[ARG]])
; CHECK-NEXT: [[RFL:%.*]] = udiv i32 [[TMP0]], 16777215
; CHECK-NEXT: ret i32 [[RFL]]
;
bb:
%val = udiv i32 %arg, 16777215
%rfl = call i32 @llvm.amdgcn.readfirstlane.i32(i32 %val)
ret i32 %rfl
}
define i32 @hoist_sdiv_i32(i32 %arg) {
; CHECK-LABEL: define i32 @hoist_sdiv_i32(
; CHECK-SAME: i32 [[ARG:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[BB:.*:]]
; CHECK-NEXT: [[TMP0:%.*]] = call i32 @llvm.amdgcn.readfirstlane.i32(i32 [[ARG]])
; CHECK-NEXT: [[RFL:%.*]] = sdiv i32 [[TMP0]], 16777215
; CHECK-NEXT: ret i32 [[RFL]]
;
bb:
%val = sdiv i32 %arg, 16777215
%rfl = call i32 @llvm.amdgcn.readfirstlane.i32(i32 %val)
ret i32 %rfl
}
define float @hoist_fdiv_f32(float %arg) {
; CHECK-LABEL: define float @hoist_fdiv_f32(
; CHECK-SAME: float [[ARG:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[BB:.*:]]
; CHECK-NEXT: [[TMP0:%.*]] = call float @llvm.amdgcn.readfirstlane.f32(float [[ARG]])
; CHECK-NEXT: [[RFL:%.*]] = fmul float [[TMP0]], 7.812500e-03
; CHECK-NEXT: ret float [[RFL]]
;
bb:
%val = fdiv float %arg, 128.0
%rfl = call float @llvm.amdgcn.readfirstlane.f32(float %val)
ret float %rfl
}
define i32 @hoist_urem_i32(i32 %arg) {
; CHECK-LABEL: define i32 @hoist_urem_i32(
; CHECK-SAME: i32 [[ARG:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[BB:.*:]]
; CHECK-NEXT: [[TMP0:%.*]] = call i32 @llvm.amdgcn.readfirstlane.i32(i32 [[ARG]])
; CHECK-NEXT: [[RFL:%.*]] = urem i32 [[TMP0]], 16777215
; CHECK-NEXT: ret i32 [[RFL]]
;
bb:
%val = urem i32 %arg, 16777215
%rfl = call i32 @llvm.amdgcn.readfirstlane.i32(i32 %val)
ret i32 %rfl
}
define i32 @hoist_srem_i32(i32 %arg) {
; CHECK-LABEL: define i32 @hoist_srem_i32(
; CHECK-SAME: i32 [[ARG:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[BB:.*:]]
; CHECK-NEXT: [[TMP0:%.*]] = call i32 @llvm.amdgcn.readfirstlane.i32(i32 [[ARG]])
; CHECK-NEXT: [[RFL:%.*]] = srem i32 [[TMP0]], 16777215
; CHECK-NEXT: ret i32 [[RFL]]
;
bb:
%val = srem i32 %arg, 16777215
%rfl = call i32 @llvm.amdgcn.readfirstlane.i32(i32 %val)
ret i32 %rfl
}
define float @hoist_frem_f32(float %arg) {
; CHECK-LABEL: define float @hoist_frem_f32(
; CHECK-SAME: float [[ARG:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[BB:.*:]]
; CHECK-NEXT: [[TMP0:%.*]] = call float @llvm.amdgcn.readfirstlane.f32(float [[ARG]])
; CHECK-NEXT: [[RFL:%.*]] = frem float [[TMP0]], 1.280000e+02
; CHECK-NEXT: ret float [[RFL]]
;
bb:
%val = frem float %arg, 128.0
%rfl = call float @llvm.amdgcn.readfirstlane.f32(float %val)
ret float %rfl
}
define i32 @hoist_shl_i32(i32 %arg) {
; CHECK-LABEL: define i32 @hoist_shl_i32(
; CHECK-SAME: i32 [[ARG:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[BB:.*:]]
; CHECK-NEXT: [[TMP0:%.*]] = call i32 @llvm.amdgcn.readfirstlane.i32(i32 [[ARG]])
; CHECK-NEXT: [[RFL:%.*]] = shl i32 [[TMP0]], 4
; CHECK-NEXT: ret i32 [[RFL]]
;
bb:
%val = shl i32 %arg, 4
%rfl = call i32 @llvm.amdgcn.readfirstlane.i32(i32 %val)
ret i32 %rfl
}
define i32 @hoist_lshr_i32(i32 %arg) {
; CHECK-LABEL: define i32 @hoist_lshr_i32(
; CHECK-SAME: i32 [[ARG:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[BB:.*:]]
; CHECK-NEXT: [[TMP0:%.*]] = call i32 @llvm.amdgcn.readfirstlane.i32(i32 [[ARG]])
; CHECK-NEXT: [[RFL:%.*]] = lshr i32 [[TMP0]], 4
; CHECK-NEXT: ret i32 [[RFL]]
;
bb:
%val = lshr i32 %arg, 4
%rfl = call i32 @llvm.amdgcn.readfirstlane.i32(i32 %val)
ret i32 %rfl
}
define i32 @hoist_ashr_i32(i32 %arg) {
; CHECK-LABEL: define i32 @hoist_ashr_i32(
; CHECK-SAME: i32 [[ARG:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[BB:.*:]]
; CHECK-NEXT: [[TMP0:%.*]] = call i32 @llvm.amdgcn.readfirstlane.i32(i32 [[ARG]])
; CHECK-NEXT: [[RFL:%.*]] = ashr i32 [[TMP0]], 4
; CHECK-NEXT: ret i32 [[RFL]]
;
bb:
%val = ashr i32 %arg, 4
%rfl = call i32 @llvm.amdgcn.readfirstlane.i32(i32 %val)
ret i32 %rfl
}
define i32 @hoist_and_i32(i32 %arg) {
; CHECK-LABEL: define i32 @hoist_and_i32(
; CHECK-SAME: i32 [[ARG:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[BB:.*:]]
; CHECK-NEXT: [[TMP0:%.*]] = call i32 @llvm.amdgcn.readfirstlane.i32(i32 [[ARG]])
; CHECK-NEXT: [[RFL:%.*]] = and i32 [[TMP0]], 16777215
; CHECK-NEXT: ret i32 [[RFL]]
;
bb:
%val = and i32 %arg, 16777215
%rfl = call i32 @llvm.amdgcn.readfirstlane.i32(i32 %val)
ret i32 %rfl
}
define i32 @hoist_or_i32(i32 %arg) {
; CHECK-LABEL: define i32 @hoist_or_i32(
; CHECK-SAME: i32 [[ARG:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[BB:.*:]]
; CHECK-NEXT: [[TMP0:%.*]] = call i32 @llvm.amdgcn.readfirstlane.i32(i32 [[ARG]])
; CHECK-NEXT: [[RFL:%.*]] = or i32 [[TMP0]], 16777215
; CHECK-NEXT: ret i32 [[RFL]]
;
bb:
%val = or i32 %arg, 16777215
%rfl = call i32 @llvm.amdgcn.readfirstlane.i32(i32 %val)
ret i32 %rfl
}
define i32 @hoist_xor_i32(i32 %arg) {
; CHECK-LABEL: define i32 @hoist_xor_i32(
; CHECK-SAME: i32 [[ARG:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[BB:.*:]]
; CHECK-NEXT: [[TMP0:%.*]] = call i32 @llvm.amdgcn.readfirstlane.i32(i32 [[ARG]])
; CHECK-NEXT: [[RFL:%.*]] = xor i32 [[TMP0]], 16777215
; CHECK-NEXT: ret i32 [[RFL]]
;
bb:
%val = xor i32 %arg, 16777215
%rfl = call i32 @llvm.amdgcn.readfirstlane.i32(i32 %val)
ret i32 %rfl
}
; test binary i64
define i64 @hoist_and_i64(i64 %arg) {
; CHECK-LABEL: define i64 @hoist_and_i64(
; CHECK-SAME: i64 [[ARG:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[BB:.*:]]
; CHECK-NEXT: [[TMP0:%.*]] = call i64 @llvm.amdgcn.readfirstlane.i64(i64 [[ARG]])
; CHECK-NEXT: [[RFL:%.*]] = and i64 [[TMP0]], 16777215
; CHECK-NEXT: ret i64 [[RFL]]
;
bb:
%val = and i64 %arg, 16777215
%rfl = call i64 @llvm.amdgcn.readfirstlane.i32(i64 %val)
ret i64 %rfl
}
define double @hoist_fadd_f64(double %arg) {
; CHECK-LABEL: define double @hoist_fadd_f64(
; CHECK-SAME: double [[ARG:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[BB:.*:]]
; CHECK-NEXT: [[TMP0:%.*]] = call double @llvm.amdgcn.readfirstlane.f64(double [[ARG]])
; CHECK-NEXT: [[RFL:%.*]] = fadd double [[TMP0]], 1.280000e+02
; CHECK-NEXT: ret double [[RFL]]
;
bb:
%val = fadd double %arg, 128.0
%rfl = call double @llvm.amdgcn.readfirstlane.f64(double %val)
ret double %rfl
}
; test constant on LHS
define i32 @hoist_sub_i32_lhs(i32 %arg) {
; CHECK-LABEL: define i32 @hoist_sub_i32_lhs(
; CHECK-SAME: i32 [[ARG:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[BB:.*:]]
; CHECK-NEXT: [[TMP0:%.*]] = call i32 @llvm.amdgcn.readfirstlane.i32(i32 [[ARG]])
; CHECK-NEXT: [[RFL:%.*]] = sub i32 16777215, [[TMP0]]
; CHECK-NEXT: ret i32 [[RFL]]
;
bb:
%val = sub i32 16777215, %arg
%rfl = call i32 @llvm.amdgcn.readfirstlane.i32(i32 %val)
ret i32 %rfl
}
define float @hoist_fsub_f32_lhs(float %arg) {
; CHECK-LABEL: define float @hoist_fsub_f32_lhs(
; CHECK-SAME: float [[ARG:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[BB:.*:]]
; CHECK-NEXT: [[TMP0:%.*]] = call float @llvm.amdgcn.readfirstlane.f32(float [[ARG]])
; CHECK-NEXT: [[RFL:%.*]] = fsub float 1.280000e+02, [[TMP0]]
; CHECK-NEXT: ret float [[RFL]]
;
bb:
%val = fsub float 128.0, %arg
%rfl = call float @llvm.amdgcn.readfirstlane.f32(float %val)
ret float %rfl
}
; test other operand is trivially uniform
define i32 @hoist_add_i32_trivially_uniform_rhs(i32 %arg, i32 %v.other) {
; CHECK-LABEL: define i32 @hoist_add_i32_trivially_uniform_rhs(
; CHECK-SAME: i32 [[ARG:%.*]], i32 [[V_OTHER:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[BB:.*:]]
; CHECK-NEXT: [[OTHER:%.*]] = call i32 @llvm.amdgcn.readfirstlane.i32(i32 [[V_OTHER]])
; CHECK-NEXT: [[TMP0:%.*]] = call i32 @llvm.amdgcn.readfirstlane.i32(i32 [[ARG]])
; CHECK-NEXT: [[RFL:%.*]] = add i32 [[TMP0]], [[OTHER]]
; CHECK-NEXT: ret i32 [[RFL]]
;
bb:
%other = call i32 @llvm.amdgcn.readfirstlane.i32(i32 %v.other)
%val = add i32 %arg, %other
%rfl = call i32 @llvm.amdgcn.readfirstlane.i32(i32 %val)
ret i32 %rfl
}
define i32 @hoist_add_i32_trivially_uniform_lhs(i32 %arg, i32 %v.other) {
; CHECK-LABEL: define i32 @hoist_add_i32_trivially_uniform_lhs(
; CHECK-SAME: i32 [[ARG:%.*]], i32 [[V_OTHER:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[BB:.*:]]
; CHECK-NEXT: [[OTHER:%.*]] = call i32 @llvm.amdgcn.readfirstlane.i32(i32 [[V_OTHER]])
; CHECK-NEXT: [[TMP0:%.*]] = call i32 @llvm.amdgcn.readfirstlane.i32(i32 [[ARG]])
; CHECK-NEXT: [[RFL:%.*]] = sub i32 [[OTHER]], [[TMP0]]
; CHECK-NEXT: ret i32 [[RFL]]
;
bb:
%other = call i32 @llvm.amdgcn.readfirstlane.i32(i32 %v.other)
%val = sub i32 %other, %arg
%rfl = call i32 @llvm.amdgcn.readfirstlane.i32(i32 %val)
ret i32 %rfl
}
; test multiple iterations
define i32 @hoist_multiple_times(i32 %arg) {
; CHECK-LABEL: define i32 @hoist_multiple_times(
; CHECK-SAME: i32 [[ARG:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[BB:.*:]]
; CHECK-NEXT: [[TMP0:%.*]] = call i32 @llvm.amdgcn.readfirstlane.i32(i32 [[ARG]])
; CHECK-NEXT: [[TMP1:%.*]] = shl i32 [[TMP0]], 2
; CHECK-NEXT: [[TMP2:%.*]] = sub i32 16777215, [[TMP1]]
; CHECK-NEXT: [[TMP3:%.*]] = xor i32 [[TMP2]], 4242
; CHECK-NEXT: [[RFL:%.*]] = add i32 [[TMP3]], 6
; CHECK-NEXT: ret i32 [[RFL]]
;
bb:
%val.0 = shl i32 %arg, 2
%val.1 = sub i32 16777215, %val.0
%val.2 = xor i32 %val.1, 4242
%val.3 = add i32 %val.2, 6
%rfl = call i32 @llvm.amdgcn.readfirstlane.i32(i32 %val.3)
ret i32 %rfl
}
; test cases where hoisting isn't possible
define i32 @cross_block_hoisting(i1 %cond, i32 %arg) {
; CHECK-LABEL: define i32 @cross_block_hoisting(
; CHECK-SAME: i1 [[COND:%.*]], i32 [[ARG:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[BB:.*]]:
; CHECK-NEXT: [[VAL:%.*]] = add i32 [[ARG]], 16777215
; CHECK-NEXT: br i1 [[COND]], label %[[THEN:.*]], label %[[END:.*]]
; CHECK: [[THEN]]:
; CHECK-NEXT: [[RFL:%.*]] = call i32 @llvm.amdgcn.readfirstlane.i32(i32 [[VAL]])
; CHECK-NEXT: br label %[[END]]
; CHECK: [[END]]:
; CHECK-NEXT: [[RES:%.*]] = phi i32 [ [[RFL]], %[[THEN]] ], [ [[VAL]], %[[BB]] ]
; CHECK-NEXT: ret i32 [[RES]]
;
bb:
%val = add i32 %arg, 16777215
br i1 %cond, label %then, label %end
then:
%rfl = call i32 @llvm.amdgcn.readfirstlane.i32(i32 %val)
br label %end
end:
%res = phi i32 [%rfl, %then], [%val, %bb]
ret i32 %res
}
define i32 @operand_is_instr(i32 %arg, ptr %src) {
; CHECK-LABEL: define i32 @operand_is_instr(
; CHECK-SAME: i32 [[ARG:%.*]], ptr [[SRC:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[BB:.*:]]
; CHECK-NEXT: [[OTHER:%.*]] = load i32, ptr [[SRC]], align 4
; CHECK-NEXT: [[VAL:%.*]] = add i32 [[ARG]], [[OTHER]]
; CHECK-NEXT: [[RFL:%.*]] = call i32 @llvm.amdgcn.readfirstlane.i32(i32 [[VAL]])
; CHECK-NEXT: ret i32 [[RFL]]
;
bb:
%other = load i32, ptr %src
%val = add i32 %arg, %other
%rfl = call i32 @llvm.amdgcn.readfirstlane.i32(i32 %val)
ret i32 %rfl
}
define i32 @operand_is_arg(i32 %arg, i32 %other) {
; CHECK-LABEL: define i32 @operand_is_arg(
; CHECK-SAME: i32 [[ARG:%.*]], i32 [[OTHER:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[BB:.*:]]
; CHECK-NEXT: [[VAL:%.*]] = add i32 [[ARG]], [[OTHER]]
; CHECK-NEXT: [[RFL:%.*]] = call i32 @llvm.amdgcn.readfirstlane.i32(i32 [[VAL]])
; CHECK-NEXT: ret i32 [[RFL]]
;
bb:
%val = add i32 %arg, %other
%rfl = call i32 @llvm.amdgcn.readfirstlane.i32(i32 %val)
ret i32 %rfl
}
; test that convergence tokens are preserved
define i32 @hoist_preserves_convergence_token(i1 %cond, i32 %arg) convergent {
; CHECK-LABEL: define i32 @hoist_preserves_convergence_token(
; CHECK-SAME: i1 [[COND:%.*]], i32 [[ARG:%.*]]) #[[ATTR1:[0-9]+]] {
; CHECK-NEXT: [[BB:.*]]:
; CHECK-NEXT: [[ENTRY:%.*]] = call token @llvm.experimental.convergence.entry()
; CHECK-NEXT: br i1 [[COND]], label %[[THEN:.*]], label %[[END:.*]]
; CHECK: [[THEN]]:
; CHECK-NEXT: [[TMP0:%.*]] = call i32 @llvm.amdgcn.readfirstlane.i32(i32 [[ARG]]) [ "convergencectrl"(token [[ENTRY]]) ]
; CHECK-NEXT: [[RFL:%.*]] = add i32 [[TMP0]], 16777215
; CHECK-NEXT: br label %[[END]]
; CHECK: [[END]]:
; CHECK-NEXT: [[RES:%.*]] = phi i32 [ [[RFL]], %[[THEN]] ], [ [[ARG]], %[[BB]] ]
; CHECK-NEXT: ret i32 [[RES]]
;
bb:
%entry = call token @llvm.experimental.convergence.entry()
br i1 %cond, label %then, label %end
then:
%val = add i32 %arg, 16777215
%rfl = call i32 @llvm.amdgcn.readfirstlane.i32(i32 %val) [ "convergencectrl"(token %entry)]
br label %end
end:
%res = phi i32 [%rfl, %then], [%arg, %bb]
ret i32 %res
}