blob: bb122ed694ce240345c3aa5f94887be45fe24f75 [file]
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -mtriple=amdgpu11.00-amd-amdhsa -passes=instcombine -S < %s | FileCheck %s --check-prefixes=GFX11
; RUN: opt -mtriple=amdgpu11.00-amd-amdhsa -mattr=+wavefrontsize64 -passes=instcombine -S < %s | FileCheck %s --check-prefixes=GFX11-W64
; RUN: opt -mtriple=amdgpu9.00-amd-amdhsa -passes=instcombine -S < %s | FileCheck %s --check-prefixes=GFX9
declare i32 @llvm.amdgcn.mbcnt.lo(i32, i32)
declare i32 @llvm.amdgcn.mbcnt.hi(i32, i32)
declare i32 @llvm.amdgcn.wave.shuffle.i32(i32, i32)
declare i64 @llvm.amdgcn.wave.shuffle.i64(i64, i32)
declare i16 @llvm.amdgcn.wave.shuffle.i16(i16, i32)
declare float @llvm.amdgcn.wave.shuffle.f32(float, i32)
declare <2 x i16> @llvm.amdgcn.wave.shuffle.v2i16(<2 x i16>, i32)
declare ptr addrspace(3) @llvm.amdgcn.wave.shuffle.p3(ptr addrspace(3), i32)
declare ptr addrspace(5) @llvm.amdgcn.wave.shuffle.p5(ptr addrspace(5), i32)
declare ptr @llvm.amdgcn.wave.shuffle.p0(ptr, i32)
declare i32 @llvm.amdgcn.ds.bpermute(i32, i32)
; Quad perm: lane ^ 1 swaps adjacent pairs.
define i32 @test_quad_perm_xor1_w32(i32 %val) {
; GFX11-LABEL: @test_quad_perm_xor1_w32(
; GFX11-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.update.dpp.i32(i32 poison, i32 [[VAL:%.*]], i32 177, i32 15, i32 15, i1 true)
; GFX11-NEXT: ret i32 [[RESULT]]
;
; GFX11-W64-LABEL: @test_quad_perm_xor1_w32(
; GFX11-W64-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX11-W64-NEXT: [[IDX:%.*]] = xor i32 [[LANE]], 1
; GFX11-W64-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 [[VAL:%.*]], i32 [[IDX]])
; GFX11-W64-NEXT: ret i32 [[RESULT]]
;
; GFX9-LABEL: @test_quad_perm_xor1_w32(
; GFX9-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX9-NEXT: [[IDX:%.*]] = xor i32 [[LANE]], 1
; GFX9-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 [[VAL:%.*]], i32 [[IDX]])
; GFX9-NEXT: ret i32 [[RESULT]]
;
%lane = call i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
%idx = xor i32 %lane, 1
%result = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 %val, i32 %idx)
ret i32 %result
}
; Quad perm: lane ^ 3 reverses within each quad.
define i32 @test_quad_perm_xor3_w32(i32 %val) {
; GFX11-LABEL: @test_quad_perm_xor3_w32(
; GFX11-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.update.dpp.i32(i32 poison, i32 [[VAL:%.*]], i32 27, i32 15, i32 15, i1 true)
; GFX11-NEXT: ret i32 [[RESULT]]
;
; GFX11-W64-LABEL: @test_quad_perm_xor3_w32(
; GFX11-W64-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX11-W64-NEXT: [[IDX:%.*]] = xor i32 [[LANE]], 3
; GFX11-W64-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 [[VAL:%.*]], i32 [[IDX]])
; GFX11-W64-NEXT: ret i32 [[RESULT]]
;
; GFX9-LABEL: @test_quad_perm_xor3_w32(
; GFX9-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX9-NEXT: [[IDX:%.*]] = xor i32 [[LANE]], 3
; GFX9-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 [[VAL:%.*]], i32 [[IDX]])
; GFX9-NEXT: ret i32 [[RESULT]]
;
%lane = call i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
%idx = xor i32 %lane, 3
%result = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 %val, i32 %idx)
ret i32 %result
}
; Half-row mirror: reverse within every 8-lane group.
define i32 @test_half_row_mirror_w32(i32 %val) {
; GFX11-LABEL: @test_half_row_mirror_w32(
; GFX11-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.update.dpp.i32(i32 poison, i32 [[VAL:%.*]], i32 321, i32 15, i32 15, i1 true)
; GFX11-NEXT: ret i32 [[RESULT]]
;
; GFX11-W64-LABEL: @test_half_row_mirror_w32(
; GFX11-W64-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX11-W64-NEXT: [[IDX:%.*]] = xor i32 [[LANE]], 7
; GFX11-W64-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 [[VAL:%.*]], i32 [[IDX]])
; GFX11-W64-NEXT: ret i32 [[RESULT]]
;
; GFX9-LABEL: @test_half_row_mirror_w32(
; GFX9-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX9-NEXT: [[IDX:%.*]] = xor i32 [[LANE]], 7
; GFX9-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 [[VAL:%.*]], i32 [[IDX]])
; GFX9-NEXT: ret i32 [[RESULT]]
;
%lane = call i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
%low3 = and i32 %lane, 7
%rev = sub i32 7, %low3
%high = and i32 %lane, -8
%idx = or i32 %high, %rev
%result = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 %val, i32 %idx)
ret i32 %result
}
; Full-row mirror: reverse within every 16-lane row.
define i32 @test_full_row_mirror_w32(i32 %val) {
; GFX11-LABEL: @test_full_row_mirror_w32(
; GFX11-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.update.dpp.i32(i32 poison, i32 [[VAL:%.*]], i32 320, i32 15, i32 15, i1 true)
; GFX11-NEXT: ret i32 [[RESULT]]
;
; GFX11-W64-LABEL: @test_full_row_mirror_w32(
; GFX11-W64-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX11-W64-NEXT: [[IDX:%.*]] = xor i32 [[LANE]], 15
; GFX11-W64-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 [[VAL:%.*]], i32 [[IDX]])
; GFX11-W64-NEXT: ret i32 [[RESULT]]
;
; GFX9-LABEL: @test_full_row_mirror_w32(
; GFX9-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX9-NEXT: [[IDX:%.*]] = xor i32 [[LANE]], 15
; GFX9-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 [[VAL:%.*]], i32 [[IDX]])
; GFX9-NEXT: ret i32 [[RESULT]]
;
%lane = call i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
%low4 = and i32 %lane, 15
%rev = sub i32 15, %low4
%high = and i32 %lane, -16
%idx = or i32 %high, %rev
%result = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 %val, i32 %idx)
ret i32 %result
}
; Row rotate right by 3 within each 16-lane row.
define i32 @test_row_rotate_right3_w32(i32 %val) {
; GFX11-LABEL: @test_row_rotate_right3_w32(
; GFX11-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.update.dpp.i32(i32 poison, i32 [[VAL:%.*]], i32 301, i32 15, i32 15, i1 true)
; GFX11-NEXT: ret i32 [[RESULT]]
;
; GFX11-W64-LABEL: @test_row_rotate_right3_w32(
; GFX11-W64-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX11-W64-NEXT: [[ROT:%.*]] = add nuw nsw i32 [[LANE]], 3
; GFX11-W64-NEXT: [[WRAPPED:%.*]] = and i32 [[ROT]], 15
; GFX11-W64-NEXT: [[HIGH:%.*]] = and i32 [[LANE]], 48
; GFX11-W64-NEXT: [[IDX:%.*]] = or disjoint i32 [[HIGH]], [[WRAPPED]]
; GFX11-W64-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 [[VAL:%.*]], i32 [[IDX]])
; GFX11-W64-NEXT: ret i32 [[RESULT]]
;
; GFX9-LABEL: @test_row_rotate_right3_w32(
; GFX9-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX9-NEXT: [[ROT:%.*]] = add nuw nsw i32 [[LANE]], 3
; GFX9-NEXT: [[WRAPPED:%.*]] = and i32 [[ROT]], 15
; GFX9-NEXT: [[HIGH:%.*]] = and i32 [[LANE]], 48
; GFX9-NEXT: [[IDX:%.*]] = or disjoint i32 [[HIGH]], [[WRAPPED]]
; GFX9-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 [[VAL:%.*]], i32 [[IDX]])
; GFX9-NEXT: ret i32 [[RESULT]]
;
%lane = call i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
%low4 = and i32 %lane, 15
%rot = add i32 %low4, 3
%wrapped = and i32 %rot, 15
%high = and i32 %lane, -16
%idx = or i32 %high, %wrapped
%result = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 %val, i32 %idx)
ret i32 %result
}
; Row share: broadcast lane 3 within each 16-lane row.
define i32 @test_row_share3_w32(i32 %val) {
; GFX11-LABEL: @test_row_share3_w32(
; GFX11-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.update.dpp.i32(i32 poison, i32 [[VAL:%.*]], i32 339, i32 15, i32 15, i1 true)
; GFX11-NEXT: ret i32 [[RESULT]]
;
; GFX11-W64-LABEL: @test_row_share3_w32(
; GFX11-W64-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX11-W64-NEXT: [[HIGH:%.*]] = and i32 [[LANE]], 48
; GFX11-W64-NEXT: [[IDX:%.*]] = or disjoint i32 [[HIGH]], 3
; GFX11-W64-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 [[VAL:%.*]], i32 [[IDX]])
; GFX11-W64-NEXT: ret i32 [[RESULT]]
;
; GFX9-LABEL: @test_row_share3_w32(
; GFX9-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX9-NEXT: [[HIGH:%.*]] = and i32 [[LANE]], 48
; GFX9-NEXT: [[IDX:%.*]] = or disjoint i32 [[HIGH]], 3
; GFX9-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 [[VAL:%.*]], i32 [[IDX]])
; GFX9-NEXT: ret i32 [[RESULT]]
;
%lane = call i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
%high = and i32 %lane, -16
%idx = or i32 %high, 3
%result = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 %val, i32 %idx)
ret i32 %result
}
; Row xmask: xor each lane with mask 5 within each 16-lane row.
define i32 @test_row_xmask5_w32(i32 %val) {
; GFX11-LABEL: @test_row_xmask5_w32(
; GFX11-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.update.dpp.i32(i32 poison, i32 [[VAL:%.*]], i32 357, i32 15, i32 15, i1 true)
; GFX11-NEXT: ret i32 [[RESULT]]
;
; GFX11-W64-LABEL: @test_row_xmask5_w32(
; GFX11-W64-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX11-W64-NEXT: [[IDX:%.*]] = xor i32 [[LANE]], 5
; GFX11-W64-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 [[VAL:%.*]], i32 [[IDX]])
; GFX11-W64-NEXT: ret i32 [[RESULT]]
;
; GFX9-LABEL: @test_row_xmask5_w32(
; GFX9-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX9-NEXT: [[IDX:%.*]] = xor i32 [[LANE]], 5
; GFX9-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 [[VAL:%.*]], i32 [[IDX]])
; GFX9-NEXT: ret i32 [[RESULT]]
;
%lane = call i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
%low4 = and i32 %lane, 15
%xored = xor i32 %low4, 5
%high = and i32 %lane, -16
%idx = or i32 %high, %xored
%result = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 %val, i32 %idx)
ret i32 %result
}
; Half-wave swap (wave64 only): lane ^ 32.
define i32 @test_half_wave_swap_w64(i32 %val) {
; GFX11-LABEL: @test_half_wave_swap_w64(
; GFX11-NEXT: [[LO:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX11-NEXT: [[IDX:%.*]] = xor i32 [[LO]], 32
; GFX11-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 [[VAL:%.*]], i32 [[IDX]])
; GFX11-NEXT: ret i32 [[RESULT]]
;
; GFX11-W64-LABEL: @test_half_wave_swap_w64(
; GFX11-W64-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.permlane64.i32(i32 [[VAL:%.*]])
; GFX11-W64-NEXT: ret i32 [[RESULT]]
;
; GFX9-LABEL: @test_half_wave_swap_w64(
; GFX9-NEXT: [[LO:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX9-NEXT: [[LANE:%.*]] = call range(i32 0, 65) i32 @llvm.amdgcn.mbcnt.hi(i32 -1, i32 [[LO]])
; GFX9-NEXT: [[IDX:%.*]] = xor i32 [[LANE]], 32
; GFX9-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 [[VAL:%.*]], i32 [[IDX]])
; GFX9-NEXT: ret i32 [[RESULT]]
;
%lo = call i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
%lane = call i32 @llvm.amdgcn.mbcnt.hi(i32 -1, i32 %lo)
%idx = xor i32 %lane, 32
%result = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 %val, i32 %idx)
ret i32 %result
}
; DPP8: rotate left by 1 within each 8-lane group.
define i32 @test_dpp8_rotate1_w32(i32 %val) {
; GFX11-LABEL: @test_dpp8_rotate1_w32(
; GFX11-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.mov.dpp8.i32(i32 [[VAL:%.*]], i32 2054353)
; GFX11-NEXT: ret i32 [[RESULT]]
;
; GFX11-W64-LABEL: @test_dpp8_rotate1_w32(
; GFX11-W64-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX11-W64-NEXT: [[ROT:%.*]] = add nuw nsw i32 [[LANE]], 1
; GFX11-W64-NEXT: [[WRAPPED:%.*]] = and i32 [[ROT]], 7
; GFX11-W64-NEXT: [[HIGH:%.*]] = and i32 [[LANE]], 56
; GFX11-W64-NEXT: [[IDX:%.*]] = or disjoint i32 [[HIGH]], [[WRAPPED]]
; GFX11-W64-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 [[VAL:%.*]], i32 [[IDX]])
; GFX11-W64-NEXT: ret i32 [[RESULT]]
;
; GFX9-LABEL: @test_dpp8_rotate1_w32(
; GFX9-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX9-NEXT: [[ROT:%.*]] = add nuw nsw i32 [[LANE]], 1
; GFX9-NEXT: [[WRAPPED:%.*]] = and i32 [[ROT]], 7
; GFX9-NEXT: [[HIGH:%.*]] = and i32 [[LANE]], 56
; GFX9-NEXT: [[IDX:%.*]] = or disjoint i32 [[HIGH]], [[WRAPPED]]
; GFX9-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 [[VAL:%.*]], i32 [[IDX]])
; GFX9-NEXT: ret i32 [[RESULT]]
;
%lane = call i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
%low3 = and i32 %lane, 7
%rot = add i32 %low3, 1
%wrapped = and i32 %rot, 7
%high = and i32 %lane, -8
%idx = or i32 %high, %wrapped
%result = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 %val, i32 %idx)
ret i32 %result
}
; Permlane16: (lane * 3) & 15, a bijection on Z/16Z.
define i32 @test_permlane16_mul3_w32(i32 %val) {
; GFX11-LABEL: @test_permlane16_mul3_w32(
; GFX11-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.permlane16.i32(i32 poison, i32 [[VAL:%.*]], i32 1392285232, i32 -629924168, i1 false, i1 false)
; GFX11-NEXT: ret i32 [[RESULT]]
;
; GFX11-W64-LABEL: @test_permlane16_mul3_w32(
; GFX11-W64-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX11-W64-NEXT: [[MUL3:%.*]] = mul nuw nsw i32 [[LANE]], 3
; GFX11-W64-NEXT: [[PERM:%.*]] = and i32 [[MUL3]], 15
; GFX11-W64-NEXT: [[HIGH:%.*]] = and i32 [[LANE]], 48
; GFX11-W64-NEXT: [[IDX:%.*]] = or disjoint i32 [[HIGH]], [[PERM]]
; GFX11-W64-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 [[VAL:%.*]], i32 [[IDX]])
; GFX11-W64-NEXT: ret i32 [[RESULT]]
;
; GFX9-LABEL: @test_permlane16_mul3_w32(
; GFX9-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX9-NEXT: [[MUL3:%.*]] = mul nuw nsw i32 [[LANE]], 3
; GFX9-NEXT: [[PERM:%.*]] = and i32 [[MUL3]], 15
; GFX9-NEXT: [[HIGH:%.*]] = and i32 [[LANE]], 48
; GFX9-NEXT: [[IDX:%.*]] = or disjoint i32 [[HIGH]], [[PERM]]
; GFX9-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 [[VAL:%.*]], i32 [[IDX]])
; GFX9-NEXT: ret i32 [[RESULT]]
;
%lane = call i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
%low4 = and i32 %lane, 15
%mul3 = mul i32 %low4, 3
%perm = and i32 %mul3, 15
%high = and i32 %lane, -16
%idx = or i32 %high, %perm
%result = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 %val, i32 %idx)
ret i32 %result
}
; PermlaneX16: lane ^ 16. Cross-row swap; identity selectors.
define i32 @test_permlanex16_xor16_w32(i32 %val) {
; GFX11-LABEL: @test_permlanex16_xor16_w32(
; GFX11-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.permlanex16.i32(i32 poison, i32 [[VAL:%.*]], i32 1985229328, i32 -19088744, i1 false, i1 false)
; GFX11-NEXT: ret i32 [[RESULT]]
;
; GFX11-W64-LABEL: @test_permlanex16_xor16_w32(
; GFX11-W64-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX11-W64-NEXT: [[IDX:%.*]] = xor i32 [[LANE]], 16
; GFX11-W64-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 [[VAL:%.*]], i32 [[IDX]])
; GFX11-W64-NEXT: ret i32 [[RESULT]]
;
; GFX9-LABEL: @test_permlanex16_xor16_w32(
; GFX9-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX9-NEXT: [[IDX:%.*]] = xor i32 [[LANE]], 16
; GFX9-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 [[VAL:%.*]], i32 [[IDX]])
; GFX9-NEXT: ret i32 [[RESULT]]
;
%lane = call i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
%idx = xor i32 %lane, 16
%result = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 %val, i32 %idx)
ret i32 %result
}
; PermlaneX16: lane ^ 17. Cross-row + XOR-by-1 within row.
define i32 @test_permlanex16_xor17_w32(i32 %val) {
; GFX11-LABEL: @test_permlanex16_xor17_w32(
; GFX11-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.permlanex16.i32(i32 poison, i32 [[VAL:%.*]], i32 1732584193, i32 -271733879, i1 false, i1 false)
; GFX11-NEXT: ret i32 [[RESULT]]
;
; GFX11-W64-LABEL: @test_permlanex16_xor17_w32(
; GFX11-W64-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX11-W64-NEXT: [[IDX:%.*]] = xor i32 [[LANE]], 17
; GFX11-W64-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 [[VAL:%.*]], i32 [[IDX]])
; GFX11-W64-NEXT: ret i32 [[RESULT]]
;
; GFX9-LABEL: @test_permlanex16_xor17_w32(
; GFX9-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX9-NEXT: [[IDX:%.*]] = xor i32 [[LANE]], 17
; GFX9-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 [[VAL:%.*]], i32 [[IDX]])
; GFX9-NEXT: ret i32 [[RESULT]]
;
%lane = call i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
%idx = xor i32 %lane, 17
%result = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 %val, i32 %idx)
ret i32 %result
}
; PermlaneX16: lane ^ 31. Cross-row + reverse within row.
define i32 @test_permlanex16_xor31_w32(i32 %val) {
; GFX11-LABEL: @test_permlanex16_xor31_w32(
; GFX11-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.permlanex16.i32(i32 poison, i32 [[VAL:%.*]], i32 -1985229329, i32 19088743, i1 false, i1 false)
; GFX11-NEXT: ret i32 [[RESULT]]
;
; GFX11-W64-LABEL: @test_permlanex16_xor31_w32(
; GFX11-W64-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX11-W64-NEXT: [[IDX:%.*]] = xor i32 [[LANE]], 31
; GFX11-W64-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 [[VAL:%.*]], i32 [[IDX]])
; GFX11-W64-NEXT: ret i32 [[RESULT]]
;
; GFX9-LABEL: @test_permlanex16_xor31_w32(
; GFX9-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX9-NEXT: [[IDX:%.*]] = xor i32 [[LANE]], 31
; GFX9-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 [[VAL:%.*]], i32 [[IDX]])
; GFX9-NEXT: ret i32 [[RESULT]]
;
%lane = call i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
%idx = xor i32 %lane, 31
%result = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 %val, i32 %idx)
ret i32 %result
}
; Float type should work the same as i32.
define float @test_quad_perm_xor1_float_w32(float %val) {
; GFX11-LABEL: @test_quad_perm_xor1_float_w32(
; GFX11-NEXT: [[RESULT:%.*]] = call float @llvm.amdgcn.update.dpp.f32(float poison, float [[VAL:%.*]], i32 177, i32 15, i32 15, i1 true)
; GFX11-NEXT: ret float [[RESULT]]
;
; GFX11-W64-LABEL: @test_quad_perm_xor1_float_w32(
; GFX11-W64-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX11-W64-NEXT: [[IDX:%.*]] = xor i32 [[LANE]], 1
; GFX11-W64-NEXT: [[RESULT:%.*]] = call float @llvm.amdgcn.wave.shuffle.f32(float [[VAL:%.*]], i32 [[IDX]])
; GFX11-W64-NEXT: ret float [[RESULT]]
;
; GFX9-LABEL: @test_quad_perm_xor1_float_w32(
; GFX9-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX9-NEXT: [[IDX:%.*]] = xor i32 [[LANE]], 1
; GFX9-NEXT: [[RESULT:%.*]] = call float @llvm.amdgcn.wave.shuffle.f32(float [[VAL:%.*]], i32 [[IDX]])
; GFX9-NEXT: ret float [[RESULT]]
;
%lane = call i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
%idx = xor i32 %lane, 1
%result = call float @llvm.amdgcn.wave.shuffle.f32(float %val, i32 %idx)
ret float %result
}
; LDS (32-bit) pointer should optimize the same as i32: the gate must not
; reject 32-bit pointer types via Type::getPrimitiveSizeInBits().
define ptr addrspace(3) @test_quad_perm_xor1_ptr3_w32(ptr addrspace(3) %val) {
; GFX11-LABEL: @test_quad_perm_xor1_ptr3_w32(
; GFX11-NEXT: [[RESULT:%.*]] = call ptr addrspace(3) @llvm.amdgcn.update.dpp.p3(ptr addrspace(3) poison, ptr addrspace(3) [[VAL:%.*]], i32 177, i32 15, i32 15, i1 true)
; GFX11-NEXT: ret ptr addrspace(3) [[RESULT]]
;
; GFX11-W64-LABEL: @test_quad_perm_xor1_ptr3_w32(
; GFX11-W64-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX11-W64-NEXT: [[IDX:%.*]] = xor i32 [[LANE]], 1
; GFX11-W64-NEXT: [[RESULT:%.*]] = call ptr addrspace(3) @llvm.amdgcn.wave.shuffle.p3(ptr addrspace(3) [[VAL:%.*]], i32 [[IDX]])
; GFX11-W64-NEXT: ret ptr addrspace(3) [[RESULT]]
;
; GFX9-LABEL: @test_quad_perm_xor1_ptr3_w32(
; GFX9-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX9-NEXT: [[IDX:%.*]] = xor i32 [[LANE]], 1
; GFX9-NEXT: [[RESULT:%.*]] = call ptr addrspace(3) @llvm.amdgcn.wave.shuffle.p3(ptr addrspace(3) [[VAL:%.*]], i32 [[IDX]])
; GFX9-NEXT: ret ptr addrspace(3) [[RESULT]]
;
%lane = call i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
%idx = xor i32 %lane, 1
%result = call ptr addrspace(3) @llvm.amdgcn.wave.shuffle.p3(ptr addrspace(3) %val, i32 %idx)
ret ptr addrspace(3) %result
}
; Scratch (32-bit) pointer, should optimize like other 32-bit pointers.
define ptr addrspace(5) @test_quad_perm_xor1_ptr5_w32(ptr addrspace(5) %val) {
; GFX11-LABEL: @test_quad_perm_xor1_ptr5_w32(
; GFX11-NEXT: [[RESULT:%.*]] = call ptr addrspace(5) @llvm.amdgcn.update.dpp.p5(ptr addrspace(5) poison, ptr addrspace(5) [[VAL:%.*]], i32 177, i32 15, i32 15, i1 true)
; GFX11-NEXT: ret ptr addrspace(5) [[RESULT]]
;
; GFX11-W64-LABEL: @test_quad_perm_xor1_ptr5_w32(
; GFX11-W64-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX11-W64-NEXT: [[IDX:%.*]] = xor i32 [[LANE]], 1
; GFX11-W64-NEXT: [[RESULT:%.*]] = call ptr addrspace(5) @llvm.amdgcn.wave.shuffle.p5(ptr addrspace(5) [[VAL:%.*]], i32 [[IDX]])
; GFX11-W64-NEXT: ret ptr addrspace(5) [[RESULT]]
;
; GFX9-LABEL: @test_quad_perm_xor1_ptr5_w32(
; GFX9-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX9-NEXT: [[IDX:%.*]] = xor i32 [[LANE]], 1
; GFX9-NEXT: [[RESULT:%.*]] = call ptr addrspace(5) @llvm.amdgcn.wave.shuffle.p5(ptr addrspace(5) [[VAL:%.*]], i32 [[IDX]])
; GFX9-NEXT: ret ptr addrspace(5) [[RESULT]]
;
%lane = call i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
%idx = xor i32 %lane, 1
%result = call ptr addrspace(5) @llvm.amdgcn.wave.shuffle.p5(ptr addrspace(5) %val, i32 %idx)
ret ptr addrspace(5) %result
}
; <2 x i16> vector (32-bit), should optimize like i32.
define <2 x i16> @test_quad_perm_xor1_v2i16_w32(<2 x i16> %val) {
; GFX11-LABEL: @test_quad_perm_xor1_v2i16_w32(
; GFX11-NEXT: [[RESULT:%.*]] = call <2 x i16> @llvm.amdgcn.update.dpp.v2i16(<2 x i16> poison, <2 x i16> [[VAL:%.*]], i32 177, i32 15, i32 15, i1 true)
; GFX11-NEXT: ret <2 x i16> [[RESULT]]
;
; GFX11-W64-LABEL: @test_quad_perm_xor1_v2i16_w32(
; GFX11-W64-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX11-W64-NEXT: [[IDX:%.*]] = xor i32 [[LANE]], 1
; GFX11-W64-NEXT: [[RESULT:%.*]] = call <2 x i16> @llvm.amdgcn.wave.shuffle.v2i16(<2 x i16> [[VAL:%.*]], i32 [[IDX]])
; GFX11-W64-NEXT: ret <2 x i16> [[RESULT]]
;
; GFX9-LABEL: @test_quad_perm_xor1_v2i16_w32(
; GFX9-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX9-NEXT: [[IDX:%.*]] = xor i32 [[LANE]], 1
; GFX9-NEXT: [[RESULT:%.*]] = call <2 x i16> @llvm.amdgcn.wave.shuffle.v2i16(<2 x i16> [[VAL:%.*]], i32 [[IDX]])
; GFX9-NEXT: ret <2 x i16> [[RESULT]]
;
%lane = call i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
%idx = xor i32 %lane, 1
%result = call <2 x i16> @llvm.amdgcn.wave.shuffle.v2i16(<2 x i16> %val, i32 %idx)
ret <2 x i16> %result
}
; Half-row-share with <2 x i16>: falls back to ds_swizzle on GFX9, using the bitcast path.
define <2 x i16> @test_half_row_share3_v2i16(<2 x i16> %val) {
; GFX11-LABEL: @test_half_row_share3_v2i16(
; GFX11-NEXT: [[RESULT:%.*]] = call <2 x i16> @llvm.amdgcn.mov.dpp8.v2i16(<2 x i16> [[VAL:%.*]], i32 7190235)
; GFX11-NEXT: ret <2 x i16> [[RESULT]]
;
; GFX11-W64-LABEL: @test_half_row_share3_v2i16(
; GFX11-W64-NEXT: [[RESULT:%.*]] = call <2 x i16> @llvm.amdgcn.mov.dpp8.v2i16(<2 x i16> [[VAL:%.*]], i32 7190235)
; GFX11-W64-NEXT: ret <2 x i16> [[RESULT]]
;
; GFX9-LABEL: @test_half_row_share3_v2i16(
; GFX9-NEXT: [[TMP1:%.*]] = bitcast <2 x i16> [[VAL:%.*]] to i32
; GFX9-NEXT: [[TMP2:%.*]] = call i32 @llvm.amdgcn.ds.swizzle(i32 [[TMP1]], i32 120)
; GFX9-NEXT: [[RESULT:%.*]] = bitcast i32 [[TMP2]] to <2 x i16>
; GFX9-NEXT: ret <2 x i16> [[RESULT]]
;
%lo = call i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
%tid = call i32 @llvm.amdgcn.mbcnt.hi(i32 -1, i32 %lo)
%masked = and i32 %tid, -8
%idx = or i32 %masked, 3
%result = call <2 x i16> @llvm.amdgcn.wave.shuffle.v2i16(<2 x i16> %val, i32 %idx)
ret <2 x i16> %result
}
; Negative: 64-bit type, should not optimize.
define i64 @test_quad_perm_xor1_i64_negative(i64 %val) {
; GFX11-LABEL: @test_quad_perm_xor1_i64_negative(
; GFX11-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX11-NEXT: [[IDX:%.*]] = xor i32 [[LANE]], 1
; GFX11-NEXT: [[RESULT:%.*]] = call i64 @llvm.amdgcn.wave.shuffle.i64(i64 [[VAL:%.*]], i32 [[IDX]])
; GFX11-NEXT: ret i64 [[RESULT]]
;
; GFX11-W64-LABEL: @test_quad_perm_xor1_i64_negative(
; GFX11-W64-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX11-W64-NEXT: [[IDX:%.*]] = xor i32 [[LANE]], 1
; GFX11-W64-NEXT: [[RESULT:%.*]] = call i64 @llvm.amdgcn.wave.shuffle.i64(i64 [[VAL:%.*]], i32 [[IDX]])
; GFX11-W64-NEXT: ret i64 [[RESULT]]
;
; GFX9-LABEL: @test_quad_perm_xor1_i64_negative(
; GFX9-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX9-NEXT: [[IDX:%.*]] = xor i32 [[LANE]], 1
; GFX9-NEXT: [[RESULT:%.*]] = call i64 @llvm.amdgcn.wave.shuffle.i64(i64 [[VAL:%.*]], i32 [[IDX]])
; GFX9-NEXT: ret i64 [[RESULT]]
;
%lane = call i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
%idx = xor i32 %lane, 1
%result = call i64 @llvm.amdgcn.wave.shuffle.i64(i64 %val, i32 %idx)
ret i64 %result
}
; Negative: 64-bit pointer, should not optimize.
define ptr @test_quad_perm_xor1_p0_negative(ptr %val) {
; GFX11-LABEL: @test_quad_perm_xor1_p0_negative(
; GFX11-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX11-NEXT: [[IDX:%.*]] = xor i32 [[LANE]], 1
; GFX11-NEXT: [[RESULT:%.*]] = call ptr @llvm.amdgcn.wave.shuffle.p0(ptr [[VAL:%.*]], i32 [[IDX]])
; GFX11-NEXT: ret ptr [[RESULT]]
;
; GFX11-W64-LABEL: @test_quad_perm_xor1_p0_negative(
; GFX11-W64-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX11-W64-NEXT: [[IDX:%.*]] = xor i32 [[LANE]], 1
; GFX11-W64-NEXT: [[RESULT:%.*]] = call ptr @llvm.amdgcn.wave.shuffle.p0(ptr [[VAL:%.*]], i32 [[IDX]])
; GFX11-W64-NEXT: ret ptr [[RESULT]]
;
; GFX9-LABEL: @test_quad_perm_xor1_p0_negative(
; GFX9-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX9-NEXT: [[IDX:%.*]] = xor i32 [[LANE]], 1
; GFX9-NEXT: [[RESULT:%.*]] = call ptr @llvm.amdgcn.wave.shuffle.p0(ptr [[VAL:%.*]], i32 [[IDX]])
; GFX9-NEXT: ret ptr [[RESULT]]
;
%lane = call i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
%idx = xor i32 %lane, 1
%result = call ptr @llvm.amdgcn.wave.shuffle.p0(ptr %val, i32 %idx)
ret ptr %result
}
; Negative: 16-bit type, should not optimize.
define i16 @test_quad_perm_xor1_i16_negative(i16 %val) {
; GFX11-LABEL: @test_quad_perm_xor1_i16_negative(
; GFX11-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX11-NEXT: [[IDX:%.*]] = xor i32 [[LANE]], 1
; GFX11-NEXT: [[RESULT:%.*]] = call i16 @llvm.amdgcn.wave.shuffle.i16(i16 [[VAL:%.*]], i32 [[IDX]])
; GFX11-NEXT: ret i16 [[RESULT]]
;
; GFX11-W64-LABEL: @test_quad_perm_xor1_i16_negative(
; GFX11-W64-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX11-W64-NEXT: [[IDX:%.*]] = xor i32 [[LANE]], 1
; GFX11-W64-NEXT: [[RESULT:%.*]] = call i16 @llvm.amdgcn.wave.shuffle.i16(i16 [[VAL:%.*]], i32 [[IDX]])
; GFX11-W64-NEXT: ret i16 [[RESULT]]
;
; GFX9-LABEL: @test_quad_perm_xor1_i16_negative(
; GFX9-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX9-NEXT: [[IDX:%.*]] = xor i32 [[LANE]], 1
; GFX9-NEXT: [[RESULT:%.*]] = call i16 @llvm.amdgcn.wave.shuffle.i16(i16 [[VAL:%.*]], i32 [[IDX]])
; GFX9-NEXT: ret i16 [[RESULT]]
;
%lane = call i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
%idx = xor i32 %lane, 1
%result = call i16 @llvm.amdgcn.wave.shuffle.i16(i16 %val, i32 %idx)
ret i16 %result
}
; Negative: poison index, should not optimize.
define i32 @test_poison_index_negative(i32 %val) {
; GFX11-LABEL: @test_poison_index_negative(
; GFX11-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 [[VAL:%.*]], i32 poison)
; GFX11-NEXT: ret i32 [[RESULT]]
;
; GFX11-W64-LABEL: @test_poison_index_negative(
; GFX11-W64-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 [[VAL:%.*]], i32 poison)
; GFX11-W64-NEXT: ret i32 [[RESULT]]
;
; GFX9-LABEL: @test_poison_index_negative(
; GFX9-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 [[VAL:%.*]], i32 poison)
; GFX9-NEXT: ret i32 [[RESULT]]
;
%result = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 %val, i32 poison)
ret i32 %result
}
; Negative: non-constant index, should not be optimized.
define i32 @test_nonconstant_shuffle_w32(i32 %val, i32 %idx) {
; GFX11-LABEL: @test_nonconstant_shuffle_w32(
; GFX11-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 [[VAL:%.*]], i32 [[IDX:%.*]])
; GFX11-NEXT: ret i32 [[RESULT]]
;
; GFX11-W64-LABEL: @test_nonconstant_shuffle_w32(
; GFX11-W64-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 [[VAL:%.*]], i32 [[IDX:%.*]])
; GFX11-W64-NEXT: ret i32 [[RESULT]]
;
; GFX9-LABEL: @test_nonconstant_shuffle_w32(
; GFX9-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 [[VAL:%.*]], i32 [[IDX:%.*]])
; GFX9-NEXT: ret i32 [[RESULT]]
;
%result = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 %val, i32 %idx)
ret i32 %result
}
; Identity shuffle: lane_id itself.
define i32 @test_identity_shuffle_w32(i32 %val) {
; GFX11-LABEL: @test_identity_shuffle_w32(
; GFX11-NEXT: ret i32 [[RESULT:%.*]]
;
; GFX11-W64-LABEL: @test_identity_shuffle_w32(
; GFX11-W64-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX11-W64-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 [[VAL:%.*]], i32 [[LANE]])
; GFX11-W64-NEXT: ret i32 [[RESULT]]
;
; GFX9-LABEL: @test_identity_shuffle_w32(
; GFX9-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX9-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 [[VAL:%.*]], i32 [[LANE]])
; GFX9-NEXT: ret i32 [[RESULT]]
;
%lane = call i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
%result = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 %val, i32 %lane)
ret i32 %result
}
; Negative: index out of range (lane + 32 >= 32 for wave32).
define i32 @test_out_of_range_w32(i32 %val) {
; GFX11-LABEL: @test_out_of_range_w32(
; GFX11-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX11-NEXT: [[IDX:%.*]] = add nuw nsw i32 [[LANE]], 32
; GFX11-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 [[VAL:%.*]], i32 [[IDX]])
; GFX11-NEXT: ret i32 [[RESULT]]
;
; GFX11-W64-LABEL: @test_out_of_range_w32(
; GFX11-W64-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX11-W64-NEXT: [[IDX:%.*]] = add nuw nsw i32 [[LANE]], 32
; GFX11-W64-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 [[VAL:%.*]], i32 [[IDX]])
; GFX11-W64-NEXT: ret i32 [[RESULT]]
;
; GFX9-LABEL: @test_out_of_range_w32(
; GFX9-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX9-NEXT: [[IDX:%.*]] = add nuw nsw i32 [[LANE]], 32
; GFX9-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 [[VAL:%.*]], i32 [[IDX]])
; GFX9-NEXT: ret i32 [[RESULT]]
;
%lane = call i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
%idx = add i32 %lane, 32
%result = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 %val, i32 %idx)
ret i32 %result
}
; ds_bpermute with a constant shuffle pattern (quad perm via byte address).
define i32 @test_bpermute_quad_xor1_w32(i32 %val) {
; GFX11-LABEL: @test_bpermute_quad_xor1_w32(
; GFX11-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.update.dpp.i32(i32 poison, i32 [[VAL:%.*]], i32 177, i32 15, i32 15, i1 true)
; GFX11-NEXT: ret i32 [[RESULT]]
;
; GFX11-W64-LABEL: @test_bpermute_quad_xor1_w32(
; GFX11-W64-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX11-W64-NEXT: [[IDX:%.*]] = shl nuw nsw i32 [[LANE]], 2
; GFX11-W64-NEXT: [[ADDR:%.*]] = xor i32 [[IDX]], 4
; GFX11-W64-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.ds.bpermute(i32 [[ADDR]], i32 [[VAL:%.*]])
; GFX11-W64-NEXT: ret i32 [[RESULT]]
;
; GFX9-LABEL: @test_bpermute_quad_xor1_w32(
; GFX9-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX9-NEXT: [[IDX:%.*]] = shl nuw nsw i32 [[LANE]], 2
; GFX9-NEXT: [[ADDR:%.*]] = xor i32 [[IDX]], 4
; GFX9-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.ds.bpermute(i32 [[ADDR]], i32 [[VAL:%.*]])
; GFX9-NEXT: ret i32 [[RESULT]]
;
%lane = call i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
%idx = xor i32 %lane, 1
%addr = shl i32 %idx, 2
%result = call i32 @llvm.amdgcn.ds.bpermute(i32 %addr, i32 %val)
ret i32 %result
}
; XOR-by-5 within each 16-lane row. On GFX10+ this matches DPP row_xmask;
; on GFX9 row_xmask is unavailable, so the generic ds_swizzle bitmask path
; takes over: AND=0x1F, OR=0, XOR=5 -> 5151.
define i32 @test_xor5_bitmask(i32 %val) {
; GFX11-LABEL: @test_xor5_bitmask(
; GFX11-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.update.dpp.i32(i32 poison, i32 [[VAL:%.*]], i32 357, i32 15, i32 15, i1 true)
; GFX11-NEXT: ret i32 [[RESULT]]
;
; GFX11-W64-LABEL: @test_xor5_bitmask(
; GFX11-W64-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.update.dpp.i32(i32 poison, i32 [[VAL:%.*]], i32 357, i32 15, i32 15, i1 true)
; GFX11-W64-NEXT: ret i32 [[RESULT]]
;
; GFX9-LABEL: @test_xor5_bitmask(
; GFX9-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.ds.swizzle(i32 [[VAL:%.*]], i32 5151)
; GFX9-NEXT: ret i32 [[RESULT]]
;
%lo = call i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
%lane = call i32 @llvm.amdgcn.mbcnt.hi(i32 -1, i32 %lo)
%idx = xor i32 %lane, 5
%result = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 %val, i32 %idx)
ret i32 %result
}
; XOR-by-16 (cross-row). On GFX11 this matches permlanex16; on GFX9 neither
; permlanex16 nor row_xmask exist, so the bitmask path catches it:
; AND=0x1F, OR=0, XOR=16 -> 16415.
define i32 @test_xor16_bitmask(i32 %val) {
; GFX11-LABEL: @test_xor16_bitmask(
; GFX11-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.permlanex16.i32(i32 poison, i32 [[VAL:%.*]], i32 1985229328, i32 -19088744, i1 false, i1 false)
; GFX11-NEXT: ret i32 [[RESULT]]
;
; GFX11-W64-LABEL: @test_xor16_bitmask(
; GFX11-W64-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.permlanex16.i32(i32 poison, i32 [[VAL:%.*]], i32 1985229328, i32 -19088744, i1 false, i1 false)
; GFX11-W64-NEXT: ret i32 [[RESULT]]
;
; GFX9-LABEL: @test_xor16_bitmask(
; GFX9-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.ds.swizzle(i32 [[VAL:%.*]], i32 16415)
; GFX9-NEXT: ret i32 [[RESULT]]
;
%lo = call i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
%lane = call i32 @llvm.amdgcn.mbcnt.hi(i32 -1, i32 %lo)
%idx = xor i32 %lane, 16
%result = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 %val, i32 %idx)
ret i32 %result
}
; Broadcast lane 5 within each 16-lane row (lanes 0..15 read lane 5, lanes
; 16..31 read lane 21, etc.). On GFX10+ row_share covers it; on GFX9 there
; is no row_share, so the bitmask path emits AND=0x10, OR=5, XOR=0 -> 176.
define i32 @test_broadcast_in_rows16_bitmask(i32 %val) {
; GFX11-LABEL: @test_broadcast_in_rows16_bitmask(
; GFX11-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.update.dpp.i32(i32 poison, i32 [[VAL:%.*]], i32 341, i32 15, i32 15, i1 true)
; GFX11-NEXT: ret i32 [[RESULT]]
;
; GFX11-W64-LABEL: @test_broadcast_in_rows16_bitmask(
; GFX11-W64-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.update.dpp.i32(i32 poison, i32 [[VAL:%.*]], i32 341, i32 15, i32 15, i1 true)
; GFX11-W64-NEXT: ret i32 [[RESULT]]
;
; GFX9-LABEL: @test_broadcast_in_rows16_bitmask(
; GFX9-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.ds.swizzle(i32 [[VAL:%.*]], i32 176)
; GFX9-NEXT: ret i32 [[RESULT]]
;
%lo = call i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
%lane = call i32 @llvm.amdgcn.mbcnt.hi(i32 -1, i32 %lo)
%hi = and i32 %lane, -16
%idx = or i32 %hi, 5
%result = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 %val, i32 %idx)
ret i32 %result
}
; Rotate-left-by-1 using mbcnt.lo only (wave32 ID form); folds to ds_swizzle
; rotate mode (imm=0xC020) on GFX11 wave32, but not on wave64 targets (GFX11-W64,
; GFX9) where mbcnt.lo alone is not the full lane ID.
define i32 @test_rotate_add1_w32(i32 %val) {
; GFX11-LABEL: @test_rotate_add1_w32(
; GFX11-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.ds.swizzle(i32 [[VAL:%.*]], i32 49184)
; GFX11-NEXT: ret i32 [[RESULT]]
;
; GFX11-W64-LABEL: @test_rotate_add1_w32(
; GFX11-W64-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX11-W64-NEXT: [[ADD:%.*]] = add nuw nsw i32 [[LANE]], 1
; GFX11-W64-NEXT: [[IDX:%.*]] = and i32 [[ADD]], 31
; GFX11-W64-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 [[VAL:%.*]], i32 [[IDX]])
; GFX11-W64-NEXT: ret i32 [[RESULT]]
;
; GFX9-LABEL: @test_rotate_add1_w32(
; GFX9-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX9-NEXT: [[ADD:%.*]] = add nuw nsw i32 [[LANE]], 1
; GFX9-NEXT: [[IDX:%.*]] = and i32 [[ADD]], 31
; GFX9-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 [[VAL:%.*]], i32 [[IDX]])
; GFX9-NEXT: ret i32 [[RESULT]]
;
%lane = call i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
%add = add i32 %lane, 1
%idx = and i32 %add, 31
%result = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 %val, i32 %idx)
ret i32 %result
}
; Rotate-right-by-1 canonicalized to rotate-left-by-31; folds to ds_swizzle
; rotate mode (imm=0xC3E0) on GFX11 wave32, but not on wave64 targets (GFX11-W64,
; GFX9) where mbcnt.lo alone is not the full lane ID.
define i32 @test_rotate_sub1_w32(i32 %val) {
; GFX11-LABEL: @test_rotate_sub1_w32(
; GFX11-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.ds.swizzle(i32 [[VAL:%.*]], i32 50144)
; GFX11-NEXT: ret i32 [[RESULT]]
;
; GFX11-W64-LABEL: @test_rotate_sub1_w32(
; GFX11-W64-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX11-W64-NEXT: [[ADD:%.*]] = add nuw nsw i32 [[LANE]], 31
; GFX11-W64-NEXT: [[IDX:%.*]] = and i32 [[ADD]], 31
; GFX11-W64-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 [[VAL:%.*]], i32 [[IDX]])
; GFX11-W64-NEXT: ret i32 [[RESULT]]
;
; GFX9-LABEL: @test_rotate_sub1_w32(
; GFX9-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX9-NEXT: [[ADD:%.*]] = add nuw nsw i32 [[LANE]], 31
; GFX9-NEXT: [[IDX:%.*]] = and i32 [[ADD]], 31
; GFX9-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 [[VAL:%.*]], i32 [[IDX]])
; GFX9-NEXT: ret i32 [[RESULT]]
;
%lane = call i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
%add = add i32 %lane, 31
%idx = and i32 %add, 31
%result = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 %val, i32 %idx)
ret i32 %result
}
; Same rotate-left-by-1 via ds_bpermute (byte-addressed); folds to ds_swizzle
; rotate mode (imm=0xC020) on GFX11 wave32, but not on wave64 targets (GFX11-W64,
; GFX9) where mbcnt.lo alone is not the full lane ID.
define i32 @test_bpermute_rotate_add1_w32(i32 %val) {
; GFX11-LABEL: @test_bpermute_rotate_add1_w32(
; GFX11-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.ds.swizzle(i32 [[VAL:%.*]], i32 49184)
; GFX11-NEXT: ret i32 [[RESULT]]
;
; GFX11-W64-LABEL: @test_bpermute_rotate_add1_w32(
; GFX11-W64-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX11-W64-NEXT: [[ADD:%.*]] = shl nuw nsw i32 [[LANE]], 2
; GFX11-W64-NEXT: [[IDX:%.*]] = add nuw nsw i32 [[ADD]], 4
; GFX11-W64-NEXT: [[ADDR:%.*]] = and i32 [[IDX]], 124
; GFX11-W64-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.ds.bpermute(i32 [[ADDR]], i32 [[VAL:%.*]])
; GFX11-W64-NEXT: ret i32 [[RESULT]]
;
; GFX9-LABEL: @test_bpermute_rotate_add1_w32(
; GFX9-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX9-NEXT: [[ADD:%.*]] = shl nuw nsw i32 [[LANE]], 2
; GFX9-NEXT: [[IDX:%.*]] = add nuw nsw i32 [[ADD]], 4
; GFX9-NEXT: [[ADDR:%.*]] = and i32 [[IDX]], 124
; GFX9-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.ds.bpermute(i32 [[ADDR]], i32 [[VAL:%.*]])
; GFX9-NEXT: ret i32 [[RESULT]]
;
%lane = call i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
%add = add i32 %lane, 1
%idx = and i32 %add, 31
%addr = shl i32 %idx, 2
%result = call i32 @llvm.amdgcn.ds.bpermute(i32 %addr, i32 %val)
ret i32 %result
}
; Wave64 rotate-left-by-1 with both 32-lane groups rotating independently;
; folds to ds_swizzle rotate mode on all targets.
define i32 @test_rotate_add1_w64(i32 %val) {
; GFX11-LABEL: @test_rotate_add1_w64(
; GFX11-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.ds.swizzle(i32 [[VAL:%.*]], i32 49184)
; GFX11-NEXT: ret i32 [[RESULT]]
;
; GFX11-W64-LABEL: @test_rotate_add1_w64(
; GFX11-W64-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.ds.swizzle(i32 [[VAL:%.*]], i32 49184)
; GFX11-W64-NEXT: ret i32 [[RESULT]]
;
; GFX9-LABEL: @test_rotate_add1_w64(
; GFX9-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.ds.swizzle(i32 [[VAL:%.*]], i32 49184)
; GFX9-NEXT: ret i32 [[RESULT]]
;
%lo = call i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
%lane = call i32 @llvm.amdgcn.mbcnt.hi(i32 -1, i32 %lo)
%low5 = and i32 %lane, 31
%add = add i32 %low5, 1
%rot = and i32 %add, 31
%hi = and i32 %lane, 32
%idx = or i32 %rot, %hi
%result = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 %val, i32 %idx)
ret i32 %result
}
; Negative: full-wave64 rotate crosses the 32-lane group boundary, so
; hasPeriodicLayout<32> rejects it and no fold occurs.
define i32 @test_rotate_add1_full_w64(i32 %val) {
; GFX11-LABEL: @test_rotate_add1_full_w64(
; GFX11-NEXT: [[LO:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX11-NEXT: [[ADD:%.*]] = add nuw nsw i32 [[LO]], 1
; GFX11-NEXT: [[IDX:%.*]] = and i32 [[ADD]], 63
; GFX11-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 [[VAL:%.*]], i32 [[IDX]])
; GFX11-NEXT: ret i32 [[RESULT]]
;
; GFX11-W64-LABEL: @test_rotate_add1_full_w64(
; GFX11-W64-NEXT: [[LO:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX11-W64-NEXT: [[LANE:%.*]] = call range(i32 0, 65) i32 @llvm.amdgcn.mbcnt.hi(i32 -1, i32 [[LO]])
; GFX11-W64-NEXT: [[ADD:%.*]] = add nuw nsw i32 [[LANE]], 1
; GFX11-W64-NEXT: [[IDX:%.*]] = and i32 [[ADD]], 63
; GFX11-W64-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 [[VAL:%.*]], i32 [[IDX]])
; GFX11-W64-NEXT: ret i32 [[RESULT]]
;
; GFX9-LABEL: @test_rotate_add1_full_w64(
; GFX9-NEXT: [[LO:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX9-NEXT: [[LANE:%.*]] = call range(i32 0, 65) i32 @llvm.amdgcn.mbcnt.hi(i32 -1, i32 [[LO]])
; GFX9-NEXT: [[ADD:%.*]] = add nuw nsw i32 [[LANE]], 1
; GFX9-NEXT: [[IDX:%.*]] = and i32 [[ADD]], 63
; GFX9-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 [[VAL:%.*]], i32 [[IDX]])
; GFX9-NEXT: ret i32 [[RESULT]]
;
%lo = call i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
%lane = call i32 @llvm.amdgcn.mbcnt.hi(i32 -1, i32 %lo)
%add = add i32 %lane, 1
%idx = and i32 %add, 63
%result = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 %val, i32 %idx)
ret i32 %result
}
; Identity shuffle (add %lane,0 folds to %lane). On GFX11 wave32 this folds to
; the source value; on wave64 targets (GFX11-W64, GFX9) mbcnt.lo alone is not
; the full lane ID so no fold occurs.
define i32 @test_identity_w32(i32 %val) {
; GFX11-LABEL: @test_identity_w32(
; GFX11-NEXT: ret i32 [[RESULT:%.*]]
;
; GFX11-W64-LABEL: @test_identity_w32(
; GFX11-W64-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX11-W64-NEXT: [[IDX:%.*]] = and i32 [[LANE]], 31
; GFX11-W64-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 [[VAL:%.*]], i32 [[IDX]])
; GFX11-W64-NEXT: ret i32 [[RESULT]]
;
; GFX9-LABEL: @test_identity_w32(
; GFX9-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX9-NEXT: [[IDX:%.*]] = and i32 [[LANE]], 31
; GFX9-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 [[VAL:%.*]], i32 [[IDX]])
; GFX9-NEXT: ret i32 [[RESULT]]
;
%lane = call i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
%add = add i32 %lane, 0
%idx = and i32 %add, 31
%result = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 %val, i32 %idx)
ret i32 %result
}
; Two 32-lane halves rotate by different amounts (low half by 1, high half by 2).
; On wave64 hasPeriodicLayout<32> rejects the non-uniform pattern so no fold
; occurs. On GFX11 wave32 only one 32-lane group exists so the high-half shift
; is never evaluated; the pattern collapses to a uniform rotate-by-1 and folds.
define i32 @test_rotate_asymmetric_w64(i32 %val) {
; GFX11-LABEL: @test_rotate_asymmetric_w64(
; GFX11-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.ds.swizzle(i32 [[VAL:%.*]], i32 49184)
; GFX11-NEXT: ret i32 [[RESULT]]
;
; GFX11-W64-LABEL: @test_rotate_asymmetric_w64(
; GFX11-W64-NEXT: [[LO:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX11-W64-NEXT: [[LANE:%.*]] = call range(i32 0, 65) i32 @llvm.amdgcn.mbcnt.hi(i32 -1, i32 [[LO]])
; GFX11-W64-NEXT: [[HI:%.*]] = and i32 [[LANE]], 32
; GFX11-W64-NEXT: [[HIGH_EXTRA:%.*]] = lshr exact i32 [[HI]], 5
; GFX11-W64-NEXT: [[SHIFT:%.*]] = add nuw nsw i32 [[HIGH_EXTRA]], 1
; GFX11-W64-NEXT: [[ADD:%.*]] = add nuw nsw i32 [[LANE]], [[SHIFT]]
; GFX11-W64-NEXT: [[ROT:%.*]] = and i32 [[ADD]], 31
; GFX11-W64-NEXT: [[IDX:%.*]] = or disjoint i32 [[ROT]], [[HI]]
; GFX11-W64-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 [[VAL:%.*]], i32 [[IDX]])
; GFX11-W64-NEXT: ret i32 [[RESULT]]
;
; GFX9-LABEL: @test_rotate_asymmetric_w64(
; GFX9-NEXT: [[LO:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX9-NEXT: [[LANE:%.*]] = call range(i32 0, 65) i32 @llvm.amdgcn.mbcnt.hi(i32 -1, i32 [[LO]])
; GFX9-NEXT: [[HI:%.*]] = and i32 [[LANE]], 32
; GFX9-NEXT: [[HIGH_EXTRA:%.*]] = lshr exact i32 [[HI]], 5
; GFX9-NEXT: [[SHIFT:%.*]] = add nuw nsw i32 [[HIGH_EXTRA]], 1
; GFX9-NEXT: [[ADD:%.*]] = add nuw nsw i32 [[LANE]], [[SHIFT]]
; GFX9-NEXT: [[ROT:%.*]] = and i32 [[ADD]], 31
; GFX9-NEXT: [[IDX:%.*]] = or disjoint i32 [[ROT]], [[HI]]
; GFX9-NEXT: [[RESULT:%.*]] = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 [[VAL:%.*]], i32 [[IDX]])
; GFX9-NEXT: ret i32 [[RESULT]]
;
%lo = call i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
%lane = call i32 @llvm.amdgcn.mbcnt.hi(i32 -1, i32 %lo)
%low5 = and i32 %lane, 31
%hi = and i32 %lane, 32
%high_extra = lshr i32 %hi, 5
%shift = add i32 %high_extra, 1
%add = add i32 %low5, %shift
%rot = and i32 %add, 31
%idx = or i32 %rot, %hi
%result = call i32 @llvm.amdgcn.wave.shuffle.i32(i32 %val, i32 %idx)
ret i32 %result
}
; Rotate-left-by-3 using an f32 source; createDsSwizzle bitcasts to i32.
define float @test_rotate_add3_f32_w32(float %val) {
; GFX11-LABEL: @test_rotate_add3_f32_w32(
; GFX11-NEXT: [[TMP1:%.*]] = bitcast float [[VAL:%.*]] to i32
; GFX11-NEXT: [[TMP2:%.*]] = call i32 @llvm.amdgcn.ds.swizzle(i32 [[TMP1]], i32 49248)
; GFX11-NEXT: [[RESULT:%.*]] = bitcast i32 [[TMP2]] to float
; GFX11-NEXT: ret float [[RESULT]]
;
; GFX11-W64-LABEL: @test_rotate_add3_f32_w32(
; GFX11-W64-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX11-W64-NEXT: [[ADD:%.*]] = add nuw nsw i32 [[LANE]], 3
; GFX11-W64-NEXT: [[IDX:%.*]] = and i32 [[ADD]], 31
; GFX11-W64-NEXT: [[RESULT:%.*]] = call float @llvm.amdgcn.wave.shuffle.f32(float [[VAL:%.*]], i32 [[IDX]])
; GFX11-W64-NEXT: ret float [[RESULT]]
;
; GFX9-LABEL: @test_rotate_add3_f32_w32(
; GFX9-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX9-NEXT: [[ADD:%.*]] = add nuw nsw i32 [[LANE]], 3
; GFX9-NEXT: [[IDX:%.*]] = and i32 [[ADD]], 31
; GFX9-NEXT: [[RESULT:%.*]] = call float @llvm.amdgcn.wave.shuffle.f32(float [[VAL:%.*]], i32 [[IDX]])
; GFX9-NEXT: ret float [[RESULT]]
;
%lane = call i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
%add = add i32 %lane, 3
%idx = and i32 %add, 31
%result = call float @llvm.amdgcn.wave.shuffle.f32(float %val, i32 %idx)
ret float %result
}
; Rotate-left-by-3 using a local-memory pointer source; createDsSwizzle
; ptrtoint/inttoptr-converts around the i32 ds_swizzle.
define ptr addrspace(3) @test_rotate_add3_ptr_w32(ptr addrspace(3) %val) {
; GFX11-LABEL: @test_rotate_add3_ptr_w32(
; GFX11-NEXT: [[TMP1:%.*]] = ptrtoint ptr addrspace(3) [[VAL:%.*]] to i32
; GFX11-NEXT: [[TMP2:%.*]] = call i32 @llvm.amdgcn.ds.swizzle(i32 [[TMP1]], i32 49248)
; GFX11-NEXT: [[RESULT:%.*]] = inttoptr i32 [[TMP2]] to ptr addrspace(3)
; GFX11-NEXT: ret ptr addrspace(3) [[RESULT]]
;
; GFX11-W64-LABEL: @test_rotate_add3_ptr_w32(
; GFX11-W64-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX11-W64-NEXT: [[ADD:%.*]] = add nuw nsw i32 [[LANE]], 3
; GFX11-W64-NEXT: [[IDX:%.*]] = and i32 [[ADD]], 31
; GFX11-W64-NEXT: [[RESULT:%.*]] = call ptr addrspace(3) @llvm.amdgcn.wave.shuffle.p3(ptr addrspace(3) [[VAL:%.*]], i32 [[IDX]])
; GFX11-W64-NEXT: ret ptr addrspace(3) [[RESULT]]
;
; GFX9-LABEL: @test_rotate_add3_ptr_w32(
; GFX9-NEXT: [[LANE:%.*]] = call range(i32 0, 33) i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
; GFX9-NEXT: [[ADD:%.*]] = add nuw nsw i32 [[LANE]], 3
; GFX9-NEXT: [[IDX:%.*]] = and i32 [[ADD]], 31
; GFX9-NEXT: [[RESULT:%.*]] = call ptr addrspace(3) @llvm.amdgcn.wave.shuffle.p3(ptr addrspace(3) [[VAL:%.*]], i32 [[IDX]])
; GFX9-NEXT: ret ptr addrspace(3) [[RESULT]]
;
%lane = call i32 @llvm.amdgcn.mbcnt.lo(i32 -1, i32 0)
%add = add i32 %lane, 3
%idx = and i32 %add, 31
%result = call ptr addrspace(3) @llvm.amdgcn.wave.shuffle.p3(ptr addrspace(3) %val, i32 %idx)
ret ptr addrspace(3) %result
}