[GlobalISel] Support the byte type in the IRTranslator (#196125)

> [!NOTE]
> Stacked: this PR is the base of a 2-PR stack.
> - **#196125 (this PR)** — GlobalISel byte-type support (lands first)
> - **#177908** — LoadStoreVectorizer mixed-type support (depends on
this; rebased on top)

Mirror SelectionDAG's behaviour by treating byte as integer at the
IR-to-MIR boundary:
- `getLLTForType` maps ByteType to `LLT::integer(N)`, matching the
byte->integer EVT mapping in ValueTypes.cpp.
- `translate(Constant)` handles ConstantByte by routing through
buildConstant with the underlying APInt.
- `translateBitCast` redirects only **scalar** byte<->ptr crossings to
G_INTTOPTR / G_PTRTOINT (the well-typed MIR shape for that boundary).
Vector byte<->ptr (e.g. `<N x b32>` -> ptr produced by mixed-type load
coalescing in #177908) and other legacy ptr/non-ptr IR bitcasts (AMDGPU
iN<->p3 kernarg packing, etc.) keep their historical G_BITCAST lowering
— G_INTTOPTR has no vector-src -> scalar-ptr form.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Anshil Gandhi 2026-06-05 06:06:03 -04:00 committed by GitHub
parent 25e94da798
commit 6d4cd34d86
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 1034 additions and 2 deletions

View file

@ -108,6 +108,10 @@ time (and you don't know which one), or if the value may contain uninitialized
data. For instance, if a union may hold a pointer or another type, use byte
types to load and store the value. Otherwise, use the specific type.
Byte types are supported by both SelectionDAG and GlobalISel; at the
IR-to-MIR boundary they are lowered as the equi-sized integer scalar, so the
type's mid-end bit-level semantics are not preserved through codegen.
Prefer zext over sext when legal
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

View file

@ -174,7 +174,9 @@ Here are some LLT examples and their ``EVT`` and ``Type`` equivalents:
============= ========= ======================================
``s1`` ``i1`` ``i1``
``s8`` ``i8`` ``i8``
``s8`` ``i8`` ``b8`` [#byte-as-integer]_
``s32`` ``i32`` ``i32``
``s32`` ``i32`` ``b32`` [#byte-as-integer]_
``s32`` ``f32`` ``float``
``s17`` ``i17`` ``i17``
``s16`` N/A ``{i8, i8}`` [#abi-dependent]_
@ -182,6 +184,7 @@ Here are some LLT examples and their ``EVT`` and ``Type`` equivalents:
``p0`` ``iPTR`` ``i8*``, ``i32*``, ``%opaque*``
``p2`` ``iPTR`` ``i8 addrspace(2)*``
``<4 x s32>`` ``v4f32`` ``<4 x float>``
``<4 x s8>`` ``v4i8`` ``<4 x b8>`` [#byte-as-integer]_
``s64`` ``v1f64`` ``<1 x double>``
``<3 x s32>`` ``v3i32`` ``<3 x i32>``
============= ========= ======================================
@ -212,6 +215,8 @@ on their addressspace.
.. rubric:: Footnotes
.. [#abi-dependent] This mapping is ABI dependent. Here we've assumed no additional padding is required.
.. [#byte-as-integer] The :ref:`byte type <t_byte>` ``bN`` is translated as the
equi-sized integer scalar ``sN``. See :ref:`irtranslator-byte-type`.
Generic Opcode Reference
------------------------

View file

@ -122,3 +122,25 @@ for expensive non-foldable constants. However, this can lead to unnecessary
spills and reloads in an -O0 pipeline, as these virtual registers can have long
live ranges. This can be mitigated by running a `localizer <https://github.com/llvm/llvm-project/blob/main/llvm/lib/CodeGen/GlobalISel/Localizer.cpp>`_
after the translator.
.. _irtranslator-byte-type:
Translation of the Byte Type
----------------------------
The :ref:`byte type <t_byte>` (``bN``) has no distinct GMIR representation and
is translated as the ``LLT::integer(N)``. This mirrors the
SelectionDAG behaviour, where ``bN`` maps to the same ``EVT`` as ``iN``.
* ``getLLTForType`` lowers ``ByteType`` to ``LLT::integer(N)``.
* ``ConstantByte`` is materialised via ``G_CONSTANT`` using the underlying
``APInt``, the same path as ``ConstantInt``.
* A ``bitcast`` between a byte type and a pointer (the only ptr/non-ptr
``bitcast`` IR permits with byte) is lowered to ``G_INTTOPTR`` or
``G_PTRTOINT`` rather than ``G_BITCAST``, since ``G_BITCAST`` cannot cross
the pointer/non-pointer boundary under ``MachineVerifier``.
The mid-end semantics of the byte type (per-bit poison, conditional pointer
provenance preservation) are not representable in MIR and are not consumed by
any backend pass; they are lost at the IR-to-MIR boundary.

View file

@ -4538,6 +4538,12 @@ Otherwise, when known, the specific type should be used. Each bit can be:
Any bit width from 1 bit to 2\ :sup:`23`\ (about 8 million) can be specified.
The per-bit semantics described above (poison and conditional pointer
provenance preservation) are mid-end only. At the IR-to-MIR boundary both
SelectionDAG and GlobalISel lower ``bN`` as the equi-sized integer scalar
(``iN``/``sN``); backend passes do not see the byte type and do not preserve
its bit-level semantics.
:Syntax:
::

View file

@ -285,6 +285,12 @@ Makes programs 10x faster by doing Special New Thing.
* Renamed G_CTTZ_ZERO_UNDEF to G_CTTZ_ZERO_POISON opcode to make it clear that
a zero input results in poison.
* GlobalISel's IRTranslator now supports the LLVM IR byte type (`bN`). Byte
values are translated as the equi-sized integer scalar (`sN`), `ConstantByte`
is materialised via `G_CONSTANT`, and `bitcast` between a byte type and a
pointer is lowered to `G_INTTOPTR` / `G_PTRTOINT` rather than the
verifier-illegal `G_BITCAST`.
### Changes to the Metadata Info
### Changes to the Debug Info

View file

@ -1583,9 +1583,11 @@ bool IRTranslator::translateCopy(const User &U, const Value &V,
bool IRTranslator::translateBitCast(const User &U,
MachineIRBuilder &MIRBuilder) {
Type *SrcTy = U.getOperand(0)->getType();
Type *DstTy = U.getType();
// If we're bitcasting to the source type, we can reuse the source vreg.
if (getLLTForType(*U.getOperand(0)->getType(), *DL) ==
getLLTForType(*U.getType(), *DL)) {
if (getLLTForType(*SrcTy, *DL) == getLLTForType(*DstTy, *DL)) {
// If the source is a ConstantInt then it was probably created by
// ConstantHoisting and we should leave it alone.
if (isa<ConstantInt>(U.getOperand(0)))
@ -1594,6 +1596,17 @@ bool IRTranslator::translateBitCast(const User &U,
return translateCopy(U, *U.getOperand(0), MIRBuilder);
}
// Only the scalar byte<->ptr crossing is redirected to G_INTTOPTR/G_PTRTOINT,
// which is the well-typed MIR shape for that boundary. Vector byte<->ptr
// (e.g. <N x b32> -> ptr produced by mixed-type load coalescing) and other
// legacy ptr/non-ptr IR bitcasts (AMDGPU iN<->p3 kernarg packing, etc.)
// keep their historical G_BITCAST lowering — G_INTTOPTR has no vector-src
// -> scalar-ptr form, and downstream passes already handle G_BITCAST.
if (DstTy->isPointerTy() && SrcTy->isByteTy())
return translateCast(TargetOpcode::G_INTTOPTR, U, MIRBuilder);
if (SrcTy->isPointerTy() && DstTy->isByteTy())
return translateCast(TargetOpcode::G_PTRTOINT, U, MIRBuilder);
return translateCast(TargetOpcode::G_BITCAST, U, MIRBuilder);
}
@ -3846,6 +3859,10 @@ bool IRTranslator::translate(const Constant &C, Register Reg) {
if (isa<VectorType>(CI->getType()))
CI = ConstantInt::get(CI->getContext(), CI->getValue());
EntryBuilder->buildConstant(Reg, *CI);
} else if (auto CB = dyn_cast<ConstantByte>(&C)) {
// Byte constants share G_CONSTANT with integers; the destination Reg's
// LLT (an integer LLT, see getLLTForType) determines vector splatting.
EntryBuilder->buildConstant(Reg, CB->getValue());
} else if (auto CF = dyn_cast<ConstantFP>(&C)) {
// buildFConstant expects a to-be-splatted scalar ConstantFP.
if (isa<VectorType>(CF->getType()))

View file

@ -65,6 +65,13 @@ LLT llvm::getLLTForType(Type &Ty, const DataLayout &DL) {
if (Ty.isIntegerTy())
return LLT::integer(SizeInBits);
// Byte values share an LLT with same-sized integers. The byte type's
// per-bit poison and pointer-provenance properties are mid-end concepts
// that have no MIR-level representation; matching SDAG (which lowers
// byte EVT to integer EVT) keeps verifier and target rules unified.
if (Ty.isByteTy())
return LLT::integer(SizeInBits);
return LLT::scalar(SizeInBits);
}

View file

@ -20,3 +20,169 @@ define void @addi32(i32 %arg1, i32 %arg2) {
store i32 %res, ptr addrspace(1) poison
ret void
}
; A b64 constant should materialise as a G_CONSTANT with an integer LLT.
define void @byte_constant(ptr addrspace(1) %p) {
; CHECK-LABEL: name: byte_constant
; CHECK: bb.1 (%ir-block.0):
; CHECK-NEXT: liveins: $vgpr0, $vgpr1
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $vgpr0
; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $vgpr1
; CHECK-NEXT: [[MV:%[0-9]+]]:_(p1) = G_MERGE_VALUES [[COPY]](s32), [[COPY1]](s32)
; CHECK-NEXT: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 42
; CHECK-NEXT: G_STORE [[C]](s64), [[MV]](p1) :: (store (s64) into %ir.p, addrspace 1)
; CHECK-NEXT: SI_RETURN
store b64 42, ptr addrspace(1) %p
ret void
}
; bitcast b64 -> ptr crosses the pointer/non-pointer boundary, which
; G_BITCAST cannot express; lower it as G_INTTOPTR.
define void @bitcast_b64_to_p1(b64 %b) {
; CHECK-LABEL: name: bitcast_b64_to_p1
; CHECK: bb.1 (%ir-block.0):
; CHECK-NEXT: liveins: $vgpr0, $vgpr1
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $vgpr0
; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $vgpr1
; CHECK-NEXT: [[MV:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY]](s32), [[COPY1]](s32)
; CHECK-NEXT: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 0
; CHECK-NEXT: [[INTTOPTR:%[0-9]+]]:_(p1) = G_INTTOPTR [[MV]](s64)
; CHECK-NEXT: G_STORE [[C]](s64), [[INTTOPTR]](p1) :: (store (s64) into %ir.p, addrspace 1)
; CHECK-NEXT: SI_RETURN
%p = bitcast b64 %b to ptr addrspace(1)
store i64 0, ptr addrspace(1) %p
ret void
}
; Inverse direction lowers to G_PTRTOINT.
define void @bitcast_p1_to_b64(ptr addrspace(1) %p) {
; CHECK-LABEL: name: bitcast_p1_to_b64
; CHECK: bb.1 (%ir-block.0):
; CHECK-NEXT: liveins: $vgpr0, $vgpr1
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $vgpr0
; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $vgpr1
; CHECK-NEXT: [[MV:%[0-9]+]]:_(p1) = G_MERGE_VALUES [[COPY]](s32), [[COPY1]](s32)
; CHECK-NEXT: [[DEF:%[0-9]+]]:_(p0) = G_IMPLICIT_DEF
; CHECK-NEXT: [[PTRTOINT:%[0-9]+]]:_(s64) = G_PTRTOINT [[MV]](p1)
; CHECK-NEXT: G_STORE [[PTRTOINT]](s64), [[DEF]](p0) :: (store (s64) into `ptr poison`)
; CHECK-NEXT: SI_RETURN
%b = bitcast ptr addrspace(1) %p to b64
store b64 %b, ptr poison
ret void
}
; Byte and same-sized integer share an LLT, so this bitcast collapses to a copy.
define void @bitcast_b64_to_i64(b64 %b, ptr addrspace(1) %p) {
; CHECK-LABEL: name: bitcast_b64_to_i64
; CHECK: bb.1 (%ir-block.0):
; CHECK-NEXT: liveins: $vgpr0, $vgpr1, $vgpr2, $vgpr3
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $vgpr0
; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $vgpr1
; CHECK-NEXT: [[MV:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY]](s32), [[COPY1]](s32)
; CHECK-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $vgpr2
; CHECK-NEXT: [[COPY3:%[0-9]+]]:_(s32) = COPY $vgpr3
; CHECK-NEXT: [[MV1:%[0-9]+]]:_(p1) = G_MERGE_VALUES [[COPY2]](s32), [[COPY3]](s32)
; CHECK-NEXT: G_STORE [[MV]](s64), [[MV1]](p1) :: (store (s64) into %ir.p, addrspace 1)
; CHECK-NEXT: SI_RETURN
%i = bitcast b64 %b to i64
store i64 %i, ptr addrspace(1) %p
ret void
}
; Same-LLT direction: integer to byte is also a copy.
define void @bitcast_i64_to_b64(i64 %i, ptr addrspace(1) %p) {
; CHECK-LABEL: name: bitcast_i64_to_b64
; CHECK: bb.1 (%ir-block.0):
; CHECK-NEXT: liveins: $vgpr0, $vgpr1, $vgpr2, $vgpr3
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $vgpr0
; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $vgpr1
; CHECK-NEXT: [[MV:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY]](s32), [[COPY1]](s32)
; CHECK-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $vgpr2
; CHECK-NEXT: [[COPY3:%[0-9]+]]:_(s32) = COPY $vgpr3
; CHECK-NEXT: [[MV1:%[0-9]+]]:_(p1) = G_MERGE_VALUES [[COPY2]](s32), [[COPY3]](s32)
; CHECK-NEXT: G_STORE [[MV]](s64), [[MV1]](p1) :: (store (s64) into %ir.p, addrspace 1)
; CHECK-NEXT: SI_RETURN
%b = bitcast i64 %i to b64
store b64 %b, ptr addrspace(1) %p
ret void
}
; Byte to floating point: distinct LLTs in extended mode, equal in default mode.
; AMDGPU runs in default mode, so this collapses to a copy.
define void @bitcast_b64_to_double(b64 %b, ptr addrspace(1) %p) {
; CHECK-LABEL: name: bitcast_b64_to_double
; CHECK: bb.1 (%ir-block.0):
; CHECK-NEXT: liveins: $vgpr0, $vgpr1, $vgpr2, $vgpr3
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $vgpr0
; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $vgpr1
; CHECK-NEXT: [[MV:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY]](s32), [[COPY1]](s32)
; CHECK-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $vgpr2
; CHECK-NEXT: [[COPY3:%[0-9]+]]:_(s32) = COPY $vgpr3
; CHECK-NEXT: [[MV1:%[0-9]+]]:_(p1) = G_MERGE_VALUES [[COPY2]](s32), [[COPY3]](s32)
; CHECK-NEXT: G_STORE [[MV]](s64), [[MV1]](p1) :: (store (s64) into %ir.p, addrspace 1)
; CHECK-NEXT: SI_RETURN
%d = bitcast b64 %b to double
store double %d, ptr addrspace(1) %p
ret void
}
; Negative test: a non-pointer/non-pointer bitcast with distinct LLTs must
; still emit G_BITCAST (not G_INTTOPTR / G_PTRTOINT).
define void @bitcast_v2i16_to_i32(<2 x i16> %v) {
; CHECK-LABEL: name: bitcast_v2i16_to_i32
; CHECK: bb.1 (%ir-block.0):
; CHECK-NEXT: liveins: $vgpr0
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:_(<2 x s16>) = COPY $vgpr0
; CHECK-NEXT: [[DEF:%[0-9]+]]:_(p1) = G_IMPLICIT_DEF
; CHECK-NEXT: [[BITCAST:%[0-9]+]]:_(s32) = G_BITCAST [[COPY]](<2 x s16>)
; CHECK-NEXT: G_STORE [[BITCAST]](s32), [[DEF]](p1) :: (store (s32) into `ptr addrspace(1) poison`, addrspace 1)
; CHECK-NEXT: SI_RETURN
%i = bitcast <2 x i16> %v to i32
store i32 %i, ptr addrspace(1) poison
ret void
}
; Vector of byte constants: each lane materialises via G_CONSTANT.
define void @byte_vector_constant(ptr addrspace(1) %p) {
; CHECK-LABEL: name: byte_vector_constant
; CHECK: bb.1 (%ir-block.0):
; CHECK-NEXT: liveins: $vgpr0, $vgpr1
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $vgpr0
; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $vgpr1
; CHECK-NEXT: [[MV:%[0-9]+]]:_(p1) = G_MERGE_VALUES [[COPY]](s32), [[COPY1]](s32)
; CHECK-NEXT: [[C:%[0-9]+]]:_(s8) = G_CONSTANT i8 1
; CHECK-NEXT: [[C1:%[0-9]+]]:_(s8) = G_CONSTANT i8 2
; CHECK-NEXT: [[C2:%[0-9]+]]:_(s8) = G_CONSTANT i8 3
; CHECK-NEXT: [[C3:%[0-9]+]]:_(s8) = G_CONSTANT i8 4
; CHECK-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<4 x s8>) = G_BUILD_VECTOR [[C]](s8), [[C1]](s8), [[C2]](s8), [[C3]](s8)
; CHECK-NEXT: G_STORE [[BUILD_VECTOR]](<4 x s8>), [[MV]](p1) :: (store (<4 x s8>) into %ir.p, addrspace 1)
; CHECK-NEXT: SI_RETURN
store <4 x b8> <b8 1, b8 2, b8 3, b8 4>, ptr addrspace(1) %p
ret void
}
; Loading a byte should produce an integer-LLT G_LOAD.
define b64 @load_b64(ptr addrspace(1) %p) {
; CHECK-LABEL: name: load_b64
; CHECK: bb.1 (%ir-block.0):
; CHECK-NEXT: liveins: $vgpr0, $vgpr1
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $vgpr0
; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $vgpr1
; CHECK-NEXT: [[MV:%[0-9]+]]:_(p1) = G_MERGE_VALUES [[COPY]](s32), [[COPY1]](s32)
; CHECK-NEXT: [[LOAD:%[0-9]+]]:_(s64) = G_LOAD [[MV]](p1) :: (load (s64) from %ir.p, addrspace 1)
; CHECK-NEXT: [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[LOAD]](s64)
; CHECK-NEXT: $vgpr0 = COPY [[UV]](s32)
; CHECK-NEXT: $vgpr1 = COPY [[UV1]](s32)
; CHECK-NEXT: SI_RETURN implicit $vgpr0, implicit $vgpr1
%b = load b64, ptr addrspace(1) %p
ret b64 %b
}

View file

@ -0,0 +1,793 @@
; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 5
; REQUIRES: aarch64-registered-target
; REQUIRES: amdgpu-registered-target
; REQUIRES: x86-registered-target
; RUN: llc -mtriple=aarch64-linux-gnu -O0 -stop-after=irtranslator -global-isel %s -o - 2>&1 | FileCheck %s --check-prefix=AARCH64
; RUN: llc -mtriple=amdgcn--mesa-mesa3d -O0 -stop-after=irtranslator -global-isel %s -o - 2>&1 | FileCheck %s --check-prefix=AMDGPU
; RUN: llc -mtriple=x86_64-linux-gnu -O0 -stop-after=irtranslator -global-isel %s -o - 2>&1 | FileCheck %s --check-prefix=X86
; IRTranslator handling of LLVM IR's byte type (bN), constants and loads /
; stores of byte values, and bitcasts to/from byte types. Byte values are
; translated as the equi-sized integer scalar (sN) at the IR-to-MIR boundary.
;;
;; Byte type plumbing: arguments, returns, control flow.
;;
; A byte-typed argument and return is plumbed through as the equi-sized
; integer scalar.
define b32 @byte_arg_ret_b32(b32 %b) {
; AARCH64-LABEL: name: byte_arg_ret_b32
; AARCH64: bb.1 (%ir-block.0):
; AARCH64-NEXT: liveins: $w0
; AARCH64-NEXT: {{ $}}
; AARCH64-NEXT: [[COPY:%[0-9]+]]:_(i32) = COPY $w0
; AARCH64-NEXT: $w0 = COPY [[COPY]](i32)
; AARCH64-NEXT: RET_ReallyLR implicit $w0
;
; AMDGPU-LABEL: name: byte_arg_ret_b32
; AMDGPU: bb.1 (%ir-block.0):
; AMDGPU-NEXT: liveins: $vgpr0
; AMDGPU-NEXT: {{ $}}
; AMDGPU-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $vgpr0
; AMDGPU-NEXT: $vgpr0 = COPY [[COPY]](s32)
; AMDGPU-NEXT: SI_RETURN implicit $vgpr0
;
; X86-LABEL: name: byte_arg_ret_b32
; X86: bb.1 (%ir-block.0):
; X86-NEXT: liveins: $edi
; X86-NEXT: {{ $}}
; X86-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $edi
; X86-NEXT: $eax = COPY [[COPY]](s32)
; X86-NEXT: RET 0, implicit $eax
ret b32 %b
}
; Single-bit byte (b1) maps to s1.
define void @byte_b1_store(b1 %b, ptr %p) {
; AARCH64-LABEL: name: byte_b1_store
; AARCH64: bb.1 (%ir-block.0):
; AARCH64-NEXT: liveins: $w0, $x1
; AARCH64-NEXT: {{ $}}
; AARCH64-NEXT: [[COPY:%[0-9]+]]:_(i32) = COPY $w0
; AARCH64-NEXT: [[TRUNC:%[0-9]+]]:_(i1) = G_TRUNC [[COPY]](i32)
; AARCH64-NEXT: [[COPY1:%[0-9]+]]:_(p0) = COPY $x1
; AARCH64-NEXT: G_STORE [[TRUNC]](i1), [[COPY1]](p0) :: (store (i1) into %ir.p)
; AARCH64-NEXT: RET_ReallyLR
;
; AMDGPU-LABEL: name: byte_b1_store
; AMDGPU: bb.1 (%ir-block.0):
; AMDGPU-NEXT: liveins: $vgpr0, $vgpr1, $vgpr2
; AMDGPU-NEXT: {{ $}}
; AMDGPU-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $vgpr0
; AMDGPU-NEXT: [[TRUNC:%[0-9]+]]:_(s1) = G_TRUNC [[COPY]](s32)
; AMDGPU-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $vgpr1
; AMDGPU-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $vgpr2
; AMDGPU-NEXT: [[MV:%[0-9]+]]:_(p0) = G_MERGE_VALUES [[COPY1]](s32), [[COPY2]](s32)
; AMDGPU-NEXT: G_STORE [[TRUNC]](s1), [[MV]](p0) :: (store (s1) into %ir.p)
; AMDGPU-NEXT: SI_RETURN
;
; X86-LABEL: name: byte_b1_store
; X86: bb.1 (%ir-block.0):
; X86-NEXT: liveins: $edi, $rsi
; X86-NEXT: {{ $}}
; X86-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $edi
; X86-NEXT: [[TRUNC:%[0-9]+]]:_(s1) = G_TRUNC [[COPY]](s32)
; X86-NEXT: [[COPY1:%[0-9]+]]:_(p0) = COPY $rsi
; X86-NEXT: G_STORE [[TRUNC]](s1), [[COPY1]](p0) :: (store (s1) into %ir.p)
; X86-NEXT: RET 0
store b1 %b, ptr %p
ret void
}
; Non-power-of-two byte width still maps to the same-width integer.
define void @byte_b24_store(b24 %b, ptr %p) {
; AARCH64-LABEL: name: byte_b24_store
; AARCH64: bb.1 (%ir-block.0):
; AARCH64-NEXT: liveins: $w0, $x1
; AARCH64-NEXT: {{ $}}
; AARCH64-NEXT: [[COPY:%[0-9]+]]:_(i32) = COPY $w0
; AARCH64-NEXT: [[TRUNC:%[0-9]+]]:_(i24) = G_TRUNC [[COPY]](i32)
; AARCH64-NEXT: [[COPY1:%[0-9]+]]:_(p0) = COPY $x1
; AARCH64-NEXT: G_STORE [[TRUNC]](i24), [[COPY1]](p0) :: (store (i24) into %ir.p, align 4)
; AARCH64-NEXT: RET_ReallyLR
;
; AMDGPU-LABEL: name: byte_b24_store
; AMDGPU: bb.1 (%ir-block.0):
; AMDGPU-NEXT: liveins: $vgpr0, $vgpr1, $vgpr2
; AMDGPU-NEXT: {{ $}}
; AMDGPU-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $vgpr0
; AMDGPU-NEXT: [[TRUNC:%[0-9]+]]:_(s24) = G_TRUNC [[COPY]](s32)
; AMDGPU-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $vgpr1
; AMDGPU-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $vgpr2
; AMDGPU-NEXT: [[MV:%[0-9]+]]:_(p0) = G_MERGE_VALUES [[COPY1]](s32), [[COPY2]](s32)
; AMDGPU-NEXT: G_STORE [[TRUNC]](s24), [[MV]](p0) :: (store (s24) into %ir.p, align 4)
; AMDGPU-NEXT: SI_RETURN
;
; X86-LABEL: name: byte_b24_store
; X86: bb.1 (%ir-block.0):
; X86-NEXT: liveins: $edi, $rsi
; X86-NEXT: {{ $}}
; X86-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $edi
; X86-NEXT: [[TRUNC:%[0-9]+]]:_(s24) = G_TRUNC [[COPY]](s32)
; X86-NEXT: [[COPY1:%[0-9]+]]:_(p0) = COPY $rsi
; X86-NEXT: G_STORE [[TRUNC]](s24), [[COPY1]](p0) :: (store (s24) into %ir.p, align 4)
; X86-NEXT: RET 0
store b24 %b, ptr %p
ret void
}
; phi over byte values.
define b32 @byte_phi(i1 %c, b32 %x, b32 %y) {
; AARCH64-LABEL: name: byte_phi
; AARCH64: bb.1.entry:
; AARCH64-NEXT: successors: %bb.2(0x40000000), %bb.3(0x40000000)
; AARCH64-NEXT: liveins: $w0, $w1, $w2
; AARCH64-NEXT: {{ $}}
; AARCH64-NEXT: [[COPY:%[0-9]+]]:_(i32) = COPY $w0
; AARCH64-NEXT: [[TRUNC:%[0-9]+]]:_(i8) = G_TRUNC [[COPY]](i32)
; AARCH64-NEXT: [[COPY1:%[0-9]+]]:_(i32) = COPY $w1
; AARCH64-NEXT: [[COPY2:%[0-9]+]]:_(i32) = COPY $w2
; AARCH64-NEXT: [[ASSERT_ZEXT:%[0-9]+]]:_(i8) = G_ASSERT_ZEXT [[TRUNC]], 1
; AARCH64-NEXT: [[TRUNC1:%[0-9]+]]:_(i1) = G_TRUNC [[ASSERT_ZEXT]](i8)
; AARCH64-NEXT: G_BRCOND [[TRUNC1]](i1), %bb.2
; AARCH64-NEXT: G_BR %bb.3
; AARCH64-NEXT: {{ $}}
; AARCH64-NEXT: bb.2.t:
; AARCH64-NEXT: successors: %bb.4(0x80000000)
; AARCH64-NEXT: {{ $}}
; AARCH64-NEXT: G_BR %bb.4
; AARCH64-NEXT: {{ $}}
; AARCH64-NEXT: bb.3.f:
; AARCH64-NEXT: successors: %bb.4(0x80000000)
; AARCH64-NEXT: {{ $}}
; AARCH64-NEXT: G_BR %bb.4
; AARCH64-NEXT: {{ $}}
; AARCH64-NEXT: bb.4.join:
; AARCH64-NEXT: [[PHI:%[0-9]+]]:_(i32) = G_PHI [[COPY1]](i32), %bb.2, [[COPY2]](i32), %bb.3
; AARCH64-NEXT: $w0 = COPY [[PHI]](i32)
; AARCH64-NEXT: RET_ReallyLR implicit $w0
;
; AMDGPU-LABEL: name: byte_phi
; AMDGPU: bb.1.entry:
; AMDGPU-NEXT: successors: %bb.4(0x40000000), %bb.2(0x40000000)
; AMDGPU-NEXT: liveins: $vgpr0, $vgpr1, $vgpr2
; AMDGPU-NEXT: {{ $}}
; AMDGPU-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $vgpr0
; AMDGPU-NEXT: [[TRUNC:%[0-9]+]]:_(s1) = G_TRUNC [[COPY]](s32)
; AMDGPU-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $vgpr1
; AMDGPU-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $vgpr2
; AMDGPU-NEXT: [[C:%[0-9]+]]:_(s1) = G_CONSTANT i1 true
; AMDGPU-NEXT: [[XOR:%[0-9]+]]:_(s1) = G_XOR [[TRUNC]], [[C]]
; AMDGPU-NEXT: [[INT:%[0-9]+]]:_(s1), [[INT1:%[0-9]+]]:_(s64) = G_INTRINSIC_W_SIDE_EFFECTS intrinsic(@llvm.amdgcn.if), [[XOR]](s1)
; AMDGPU-NEXT: G_BRCOND [[INT]](s1), %bb.4
; AMDGPU-NEXT: G_BR %bb.2
; AMDGPU-NEXT: {{ $}}
; AMDGPU-NEXT: bb.2.Flow:
; AMDGPU-NEXT: successors: %bb.3(0x40000000), %bb.5(0x40000000)
; AMDGPU-NEXT: {{ $}}
; AMDGPU-NEXT: [[INT2:%[0-9]+]]:_(s1), [[INT3:%[0-9]+]]:_(s64) = G_INTRINSIC_W_SIDE_EFFECTS intrinsic(@llvm.amdgcn.else), [[INT1]](s64)
; AMDGPU-NEXT: G_BRCOND [[INT2]](s1), %bb.3
; AMDGPU-NEXT: G_BR %bb.5
; AMDGPU-NEXT: {{ $}}
; AMDGPU-NEXT: bb.3.t:
; AMDGPU-NEXT: successors: %bb.5(0x80000000)
; AMDGPU-NEXT: {{ $}}
; AMDGPU-NEXT: G_BR %bb.5
; AMDGPU-NEXT: {{ $}}
; AMDGPU-NEXT: bb.4.f:
; AMDGPU-NEXT: successors: %bb.2(0x80000000)
; AMDGPU-NEXT: {{ $}}
; AMDGPU-NEXT: G_BR %bb.2
; AMDGPU-NEXT: {{ $}}
; AMDGPU-NEXT: bb.5.join:
; AMDGPU-NEXT: [[PHI:%[0-9]+]]:_(s32) = G_PHI [[COPY2]](s32), %bb.2, [[COPY1]](s32), %bb.3
; AMDGPU-NEXT: G_INTRINSIC_W_SIDE_EFFECTS intrinsic(@llvm.amdgcn.end.cf), [[INT3]](s64)
; AMDGPU-NEXT: $vgpr0 = COPY [[PHI]](s32)
; AMDGPU-NEXT: SI_RETURN implicit $vgpr0
;
; X86-LABEL: name: byte_phi
; X86: bb.1.entry:
; X86-NEXT: successors: %bb.2(0x40000000), %bb.3(0x40000000)
; X86-NEXT: liveins: $edi, $edx, $esi
; X86-NEXT: {{ $}}
; X86-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $edi
; X86-NEXT: [[TRUNC:%[0-9]+]]:_(s1) = G_TRUNC [[COPY]](s32)
; X86-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $esi
; X86-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $edx
; X86-NEXT: G_BRCOND [[TRUNC]](s1), %bb.2
; X86-NEXT: G_BR %bb.3
; X86-NEXT: {{ $}}
; X86-NEXT: bb.2.t:
; X86-NEXT: successors: %bb.4(0x80000000)
; X86-NEXT: {{ $}}
; X86-NEXT: G_BR %bb.4
; X86-NEXT: {{ $}}
; X86-NEXT: bb.3.f:
; X86-NEXT: successors: %bb.4(0x80000000)
; X86-NEXT: {{ $}}
; X86-NEXT: G_BR %bb.4
; X86-NEXT: {{ $}}
; X86-NEXT: bb.4.join:
; X86-NEXT: [[PHI:%[0-9]+]]:_(s32) = G_PHI [[COPY1]](s32), %bb.2, [[COPY2]](s32), %bb.3
; X86-NEXT: $eax = COPY [[PHI]](s32)
; X86-NEXT: RET 0, implicit $eax
entry:
br i1 %c, label %t, label %f
t:
br label %join
f:
br label %join
join:
%r = phi b32 [ %x, %t ], [ %y, %f ]
ret b32 %r
}
; select on a byte type.
define b32 @byte_select(i1 %c, b32 %x, b32 %y) {
; AARCH64-LABEL: name: byte_select
; AARCH64: bb.1 (%ir-block.0):
; AARCH64-NEXT: liveins: $w0, $w1, $w2
; AARCH64-NEXT: {{ $}}
; AARCH64-NEXT: [[COPY:%[0-9]+]]:_(i32) = COPY $w0
; AARCH64-NEXT: [[TRUNC:%[0-9]+]]:_(i8) = G_TRUNC [[COPY]](i32)
; AARCH64-NEXT: [[COPY1:%[0-9]+]]:_(i32) = COPY $w1
; AARCH64-NEXT: [[COPY2:%[0-9]+]]:_(i32) = COPY $w2
; AARCH64-NEXT: [[ASSERT_ZEXT:%[0-9]+]]:_(i8) = G_ASSERT_ZEXT [[TRUNC]], 1
; AARCH64-NEXT: [[TRUNC1:%[0-9]+]]:_(i1) = G_TRUNC [[ASSERT_ZEXT]](i8)
; AARCH64-NEXT: [[SELECT:%[0-9]+]]:_(i32) = G_SELECT [[TRUNC1]](i1), [[COPY1]], [[COPY2]]
; AARCH64-NEXT: $w0 = COPY [[SELECT]](i32)
; AARCH64-NEXT: RET_ReallyLR implicit $w0
;
; AMDGPU-LABEL: name: byte_select
; AMDGPU: bb.1 (%ir-block.0):
; AMDGPU-NEXT: liveins: $vgpr0, $vgpr1, $vgpr2
; AMDGPU-NEXT: {{ $}}
; AMDGPU-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $vgpr0
; AMDGPU-NEXT: [[TRUNC:%[0-9]+]]:_(s1) = G_TRUNC [[COPY]](s32)
; AMDGPU-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $vgpr1
; AMDGPU-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $vgpr2
; AMDGPU-NEXT: [[SELECT:%[0-9]+]]:_(s32) = G_SELECT [[TRUNC]](s1), [[COPY1]], [[COPY2]]
; AMDGPU-NEXT: $vgpr0 = COPY [[SELECT]](s32)
; AMDGPU-NEXT: SI_RETURN implicit $vgpr0
;
; X86-LABEL: name: byte_select
; X86: bb.1 (%ir-block.0):
; X86-NEXT: liveins: $edi, $edx, $esi
; X86-NEXT: {{ $}}
; X86-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $edi
; X86-NEXT: [[TRUNC:%[0-9]+]]:_(s1) = G_TRUNC [[COPY]](s32)
; X86-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $esi
; X86-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $edx
; X86-NEXT: [[SELECT:%[0-9]+]]:_(s32) = G_SELECT [[TRUNC]](s1), [[COPY1]], [[COPY2]]
; X86-NEXT: $eax = COPY [[SELECT]](s32)
; X86-NEXT: RET 0, implicit $eax
%r = select i1 %c, b32 %x, b32 %y
ret b32 %r
}
; A b8 loaded through a flat pointer.
define b8 @load_b8(ptr %p) {
; AARCH64-LABEL: name: load_b8
; AARCH64: bb.1 (%ir-block.0):
; AARCH64-NEXT: liveins: $x0
; AARCH64-NEXT: {{ $}}
; AARCH64-NEXT: [[COPY:%[0-9]+]]:_(p0) = COPY $x0
; AARCH64-NEXT: [[LOAD:%[0-9]+]]:_(i8) = G_LOAD [[COPY]](p0) :: (load (i8) from %ir.p)
; AARCH64-NEXT: [[ANYEXT:%[0-9]+]]:_(i32) = G_ANYEXT [[LOAD]](i8)
; AARCH64-NEXT: $w0 = COPY [[ANYEXT]](i32)
; AARCH64-NEXT: RET_ReallyLR implicit $w0
;
; AMDGPU-LABEL: name: load_b8
; AMDGPU: bb.1 (%ir-block.0):
; AMDGPU-NEXT: liveins: $vgpr0, $vgpr1
; AMDGPU-NEXT: {{ $}}
; AMDGPU-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $vgpr0
; AMDGPU-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $vgpr1
; AMDGPU-NEXT: [[MV:%[0-9]+]]:_(p0) = G_MERGE_VALUES [[COPY]](s32), [[COPY1]](s32)
; AMDGPU-NEXT: [[LOAD:%[0-9]+]]:_(s8) = G_LOAD [[MV]](p0) :: (load (s8) from %ir.p)
; AMDGPU-NEXT: [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[LOAD]](s8)
; AMDGPU-NEXT: $vgpr0 = COPY [[ANYEXT]](s32)
; AMDGPU-NEXT: SI_RETURN implicit $vgpr0
;
; X86-LABEL: name: load_b8
; X86: bb.1 (%ir-block.0):
; X86-NEXT: liveins: $rdi
; X86-NEXT: {{ $}}
; X86-NEXT: [[COPY:%[0-9]+]]:_(p0) = COPY $rdi
; X86-NEXT: [[LOAD:%[0-9]+]]:_(s8) = G_LOAD [[COPY]](p0) :: (load (s8) from %ir.p)
; X86-NEXT: $al = COPY [[LOAD]](s8)
; X86-NEXT: RET 0, implicit $al
%b = load b8, ptr %p
ret b8 %b
}
; A b64 constant should materialise as a G_CONSTANT with an integer LLT.
define void @byte_constant_store(ptr %p) {
; AARCH64-LABEL: name: byte_constant_store
; AARCH64: bb.1 (%ir-block.0):
; AARCH64-NEXT: liveins: $x0
; AARCH64-NEXT: {{ $}}
; AARCH64-NEXT: [[COPY:%[0-9]+]]:_(p0) = COPY $x0
; AARCH64-NEXT: [[C:%[0-9]+]]:_(i64) = G_CONSTANT i64 42
; AARCH64-NEXT: G_STORE [[C]](i64), [[COPY]](p0) :: (store (i64) into %ir.p)
; AARCH64-NEXT: RET_ReallyLR
;
; AMDGPU-LABEL: name: byte_constant_store
; AMDGPU: bb.1 (%ir-block.0):
; AMDGPU-NEXT: liveins: $vgpr0, $vgpr1
; AMDGPU-NEXT: {{ $}}
; AMDGPU-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $vgpr0
; AMDGPU-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $vgpr1
; AMDGPU-NEXT: [[MV:%[0-9]+]]:_(p0) = G_MERGE_VALUES [[COPY]](s32), [[COPY1]](s32)
; AMDGPU-NEXT: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 42
; AMDGPU-NEXT: G_STORE [[C]](s64), [[MV]](p0) :: (store (s64) into %ir.p)
; AMDGPU-NEXT: SI_RETURN
;
; X86-LABEL: name: byte_constant_store
; X86: bb.1 (%ir-block.0):
; X86-NEXT: liveins: $rdi
; X86-NEXT: {{ $}}
; X86-NEXT: [[COPY:%[0-9]+]]:_(p0) = COPY $rdi
; X86-NEXT: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 42
; X86-NEXT: G_STORE [[C]](s64), [[COPY]](p0) :: (store (s64) into %ir.p)
; X86-NEXT: RET 0
store b64 42, ptr %p
ret void
}
;;
;; Bitcasts to/from byte: same-LLT collapses to a copy, distinct-LLT keeps
;; G_BITCAST, ptr/non-ptr crossings use G_INTTOPTR / G_PTRTOINT.
;;
; Byte-to-byte bitcast of the same width is a no-op copy.
define b32 @bitcast_b32_to_b32(b32 %b) {
; AARCH64-LABEL: name: bitcast_b32_to_b32
; AARCH64: bb.1 (%ir-block.0):
; AARCH64-NEXT: liveins: $w0
; AARCH64-NEXT: {{ $}}
; AARCH64-NEXT: [[COPY:%[0-9]+]]:_(i32) = COPY $w0
; AARCH64-NEXT: $w0 = COPY [[COPY]](i32)
; AARCH64-NEXT: RET_ReallyLR implicit $w0
;
; AMDGPU-LABEL: name: bitcast_b32_to_b32
; AMDGPU: bb.1 (%ir-block.0):
; AMDGPU-NEXT: liveins: $vgpr0
; AMDGPU-NEXT: {{ $}}
; AMDGPU-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $vgpr0
; AMDGPU-NEXT: $vgpr0 = COPY [[COPY]](s32)
; AMDGPU-NEXT: SI_RETURN implicit $vgpr0
;
; X86-LABEL: name: bitcast_b32_to_b32
; X86: bb.1 (%ir-block.0):
; X86-NEXT: liveins: $edi
; X86-NEXT: {{ $}}
; X86-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $edi
; X86-NEXT: $eax = COPY [[COPY]](s32)
; X86-NEXT: RET 0, implicit $eax
%r = bitcast b32 %b to b32
ret b32 %r
}
; Vector of bytes to vector of same-width integers shares an LLT - copy.
define <4 x i8> @bitcast_v4b8_to_v4i8(<4 x b8> %v) {
; AARCH64-LABEL: name: bitcast_v4b8_to_v4i8
; AARCH64: bb.1 (%ir-block.0):
; AARCH64-NEXT: liveins: $d0
; AARCH64-NEXT: {{ $}}
; AARCH64-NEXT: [[COPY:%[0-9]+]]:_(<4 x i16>) = COPY $d0
; AARCH64-NEXT: [[TRUNC:%[0-9]+]]:_(<4 x i8>) = G_TRUNC [[COPY]](<4 x i16>)
; AARCH64-NEXT: [[ANYEXT:%[0-9]+]]:_(<4 x i16>) = G_ANYEXT [[TRUNC]](<4 x i8>)
; AARCH64-NEXT: $d0 = COPY [[ANYEXT]](<4 x i16>)
; AARCH64-NEXT: RET_ReallyLR implicit $d0
;
; AMDGPU-LABEL: name: bitcast_v4b8_to_v4i8
; AMDGPU: bb.1 (%ir-block.0):
; AMDGPU-NEXT: liveins: $vgpr0, $vgpr1, $vgpr2, $vgpr3
; AMDGPU-NEXT: {{ $}}
; AMDGPU-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $vgpr0
; AMDGPU-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $vgpr1
; AMDGPU-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $vgpr2
; AMDGPU-NEXT: [[COPY3:%[0-9]+]]:_(s32) = COPY $vgpr3
; AMDGPU-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<4 x s32>) = G_BUILD_VECTOR [[COPY]](s32), [[COPY1]](s32), [[COPY2]](s32), [[COPY3]](s32)
; AMDGPU-NEXT: [[TRUNC:%[0-9]+]]:_(<4 x s8>) = G_TRUNC [[BUILD_VECTOR]](<4 x s32>)
; AMDGPU-NEXT: [[UV:%[0-9]+]]:_(s8), [[UV1:%[0-9]+]]:_(s8), [[UV2:%[0-9]+]]:_(s8), [[UV3:%[0-9]+]]:_(s8) = G_UNMERGE_VALUES [[TRUNC]](<4 x s8>)
; AMDGPU-NEXT: [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[UV]](s8)
; AMDGPU-NEXT: [[ANYEXT1:%[0-9]+]]:_(s32) = G_ANYEXT [[UV1]](s8)
; AMDGPU-NEXT: [[ANYEXT2:%[0-9]+]]:_(s32) = G_ANYEXT [[UV2]](s8)
; AMDGPU-NEXT: [[ANYEXT3:%[0-9]+]]:_(s32) = G_ANYEXT [[UV3]](s8)
; AMDGPU-NEXT: $vgpr0 = COPY [[ANYEXT]](s32)
; AMDGPU-NEXT: $vgpr1 = COPY [[ANYEXT1]](s32)
; AMDGPU-NEXT: $vgpr2 = COPY [[ANYEXT2]](s32)
; AMDGPU-NEXT: $vgpr3 = COPY [[ANYEXT3]](s32)
; AMDGPU-NEXT: SI_RETURN implicit $vgpr0, implicit $vgpr1, implicit $vgpr2, implicit $vgpr3
;
; X86-LABEL: name: bitcast_v4b8_to_v4i8
; X86: bb.1 (%ir-block.0):
; X86-NEXT: liveins: $xmm0
; X86-NEXT: {{ $}}
; X86-NEXT: [[COPY:%[0-9]+]]:_(<16 x s8>) = COPY $xmm0
; X86-NEXT: [[UV:%[0-9]+]]:_(<4 x s8>), [[UV1:%[0-9]+]]:_(<4 x s8>), [[UV2:%[0-9]+]]:_(<4 x s8>), [[UV3:%[0-9]+]]:_(<4 x s8>) = G_UNMERGE_VALUES [[COPY]](<16 x s8>)
; X86-NEXT: [[UV4:%[0-9]+]]:_(s8), [[UV5:%[0-9]+]]:_(s8), [[UV6:%[0-9]+]]:_(s8), [[UV7:%[0-9]+]]:_(s8) = G_UNMERGE_VALUES [[UV]](<4 x s8>)
; X86-NEXT: [[DEF:%[0-9]+]]:_(s8) = G_IMPLICIT_DEF
; X86-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<16 x s8>) = G_BUILD_VECTOR [[UV4]](s8), [[UV5]](s8), [[UV6]](s8), [[UV7]](s8), [[DEF]](s8), [[DEF]](s8), [[DEF]](s8), [[DEF]](s8), [[DEF]](s8), [[DEF]](s8), [[DEF]](s8), [[DEF]](s8), [[DEF]](s8), [[DEF]](s8), [[DEF]](s8), [[DEF]](s8)
; X86-NEXT: $xmm0 = COPY [[BUILD_VECTOR]](<16 x s8>)
; X86-NEXT: RET 0, implicit $xmm0
%r = bitcast <4 x b8> %v to <4 x i8>
ret <4 x i8> %r
}
; Vector of bytes to a scalar integer with the same total size: distinct LLTs,
; G_BITCAST is required.
define i32 @bitcast_v4b8_to_i32(<4 x b8> %v) {
; AARCH64-LABEL: name: bitcast_v4b8_to_i32
; AARCH64: bb.1 (%ir-block.0):
; AARCH64-NEXT: liveins: $d0
; AARCH64-NEXT: {{ $}}
; AARCH64-NEXT: [[COPY:%[0-9]+]]:_(<4 x i16>) = COPY $d0
; AARCH64-NEXT: [[TRUNC:%[0-9]+]]:_(<4 x i8>) = G_TRUNC [[COPY]](<4 x i16>)
; AARCH64-NEXT: [[BITCAST:%[0-9]+]]:_(i32) = G_BITCAST [[TRUNC]](<4 x i8>)
; AARCH64-NEXT: $w0 = COPY [[BITCAST]](i32)
; AARCH64-NEXT: RET_ReallyLR implicit $w0
;
; AMDGPU-LABEL: name: bitcast_v4b8_to_i32
; AMDGPU: bb.1 (%ir-block.0):
; AMDGPU-NEXT: liveins: $vgpr0, $vgpr1, $vgpr2, $vgpr3
; AMDGPU-NEXT: {{ $}}
; AMDGPU-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $vgpr0
; AMDGPU-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $vgpr1
; AMDGPU-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $vgpr2
; AMDGPU-NEXT: [[COPY3:%[0-9]+]]:_(s32) = COPY $vgpr3
; AMDGPU-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<4 x s32>) = G_BUILD_VECTOR [[COPY]](s32), [[COPY1]](s32), [[COPY2]](s32), [[COPY3]](s32)
; AMDGPU-NEXT: [[TRUNC:%[0-9]+]]:_(<4 x s8>) = G_TRUNC [[BUILD_VECTOR]](<4 x s32>)
; AMDGPU-NEXT: [[BITCAST:%[0-9]+]]:_(s32) = G_BITCAST [[TRUNC]](<4 x s8>)
; AMDGPU-NEXT: $vgpr0 = COPY [[BITCAST]](s32)
; AMDGPU-NEXT: SI_RETURN implicit $vgpr0
;
; X86-LABEL: name: bitcast_v4b8_to_i32
; X86: bb.1 (%ir-block.0):
; X86-NEXT: liveins: $xmm0
; X86-NEXT: {{ $}}
; X86-NEXT: [[COPY:%[0-9]+]]:_(<16 x s8>) = COPY $xmm0
; X86-NEXT: [[UV:%[0-9]+]]:_(<4 x s8>), [[UV1:%[0-9]+]]:_(<4 x s8>), [[UV2:%[0-9]+]]:_(<4 x s8>), [[UV3:%[0-9]+]]:_(<4 x s8>) = G_UNMERGE_VALUES [[COPY]](<16 x s8>)
; X86-NEXT: [[BITCAST:%[0-9]+]]:_(s32) = G_BITCAST [[UV]](<4 x s8>)
; X86-NEXT: $eax = COPY [[BITCAST]](s32)
; X86-NEXT: RET 0, implicit $eax
%r = bitcast <4 x b8> %v to i32
ret i32 %r
}
; Scalar byte to a vector of bytes of the same total width: distinct LLTs,
; G_BITCAST is required.
define <4 x b8> @bitcast_b32_to_v4b8(b32 %b) {
; AARCH64-LABEL: name: bitcast_b32_to_v4b8
; AARCH64: bb.1 (%ir-block.0):
; AARCH64-NEXT: liveins: $w0
; AARCH64-NEXT: {{ $}}
; AARCH64-NEXT: [[COPY:%[0-9]+]]:_(i32) = COPY $w0
; AARCH64-NEXT: [[BITCAST:%[0-9]+]]:_(<4 x i8>) = G_BITCAST [[COPY]](i32)
; AARCH64-NEXT: [[ANYEXT:%[0-9]+]]:_(<4 x i16>) = G_ANYEXT [[BITCAST]](<4 x i8>)
; AARCH64-NEXT: $d0 = COPY [[ANYEXT]](<4 x i16>)
; AARCH64-NEXT: RET_ReallyLR implicit $d0
;
; AMDGPU-LABEL: name: bitcast_b32_to_v4b8
; AMDGPU: bb.1 (%ir-block.0):
; AMDGPU-NEXT: liveins: $vgpr0
; AMDGPU-NEXT: {{ $}}
; AMDGPU-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $vgpr0
; AMDGPU-NEXT: [[BITCAST:%[0-9]+]]:_(<4 x s8>) = G_BITCAST [[COPY]](s32)
; AMDGPU-NEXT: [[UV:%[0-9]+]]:_(s8), [[UV1:%[0-9]+]]:_(s8), [[UV2:%[0-9]+]]:_(s8), [[UV3:%[0-9]+]]:_(s8) = G_UNMERGE_VALUES [[BITCAST]](<4 x s8>)
; AMDGPU-NEXT: [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[UV]](s8)
; AMDGPU-NEXT: [[ANYEXT1:%[0-9]+]]:_(s32) = G_ANYEXT [[UV1]](s8)
; AMDGPU-NEXT: [[ANYEXT2:%[0-9]+]]:_(s32) = G_ANYEXT [[UV2]](s8)
; AMDGPU-NEXT: [[ANYEXT3:%[0-9]+]]:_(s32) = G_ANYEXT [[UV3]](s8)
; AMDGPU-NEXT: $vgpr0 = COPY [[ANYEXT]](s32)
; AMDGPU-NEXT: $vgpr1 = COPY [[ANYEXT1]](s32)
; AMDGPU-NEXT: $vgpr2 = COPY [[ANYEXT2]](s32)
; AMDGPU-NEXT: $vgpr3 = COPY [[ANYEXT3]](s32)
; AMDGPU-NEXT: SI_RETURN implicit $vgpr0, implicit $vgpr1, implicit $vgpr2, implicit $vgpr3
;
; X86-LABEL: name: bitcast_b32_to_v4b8
; X86: bb.1 (%ir-block.0):
; X86-NEXT: liveins: $edi
; X86-NEXT: {{ $}}
; X86-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $edi
; X86-NEXT: [[BITCAST:%[0-9]+]]:_(<4 x s8>) = G_BITCAST [[COPY]](s32)
; X86-NEXT: [[UV:%[0-9]+]]:_(s8), [[UV1:%[0-9]+]]:_(s8), [[UV2:%[0-9]+]]:_(s8), [[UV3:%[0-9]+]]:_(s8) = G_UNMERGE_VALUES [[BITCAST]](<4 x s8>)
; X86-NEXT: [[DEF:%[0-9]+]]:_(s8) = G_IMPLICIT_DEF
; X86-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<16 x s8>) = G_BUILD_VECTOR [[UV]](s8), [[UV1]](s8), [[UV2]](s8), [[UV3]](s8), [[DEF]](s8), [[DEF]](s8), [[DEF]](s8), [[DEF]](s8), [[DEF]](s8), [[DEF]](s8), [[DEF]](s8), [[DEF]](s8), [[DEF]](s8), [[DEF]](s8), [[DEF]](s8), [[DEF]](s8)
; X86-NEXT: $xmm0 = COPY [[BUILD_VECTOR]](<16 x s8>)
; X86-NEXT: RET 0, implicit $xmm0
%r = bitcast b32 %b to <4 x b8>
ret <4 x b8> %r
}
; Vector of bytes back to a scalar byte: distinct LLTs, G_BITCAST.
define b32 @bitcast_v4b8_to_b32(<4 x b8> %v) {
; AARCH64-LABEL: name: bitcast_v4b8_to_b32
; AARCH64: bb.1 (%ir-block.0):
; AARCH64-NEXT: liveins: $d0
; AARCH64-NEXT: {{ $}}
; AARCH64-NEXT: [[COPY:%[0-9]+]]:_(<4 x i16>) = COPY $d0
; AARCH64-NEXT: [[TRUNC:%[0-9]+]]:_(<4 x i8>) = G_TRUNC [[COPY]](<4 x i16>)
; AARCH64-NEXT: [[BITCAST:%[0-9]+]]:_(i32) = G_BITCAST [[TRUNC]](<4 x i8>)
; AARCH64-NEXT: $w0 = COPY [[BITCAST]](i32)
; AARCH64-NEXT: RET_ReallyLR implicit $w0
;
; AMDGPU-LABEL: name: bitcast_v4b8_to_b32
; AMDGPU: bb.1 (%ir-block.0):
; AMDGPU-NEXT: liveins: $vgpr0, $vgpr1, $vgpr2, $vgpr3
; AMDGPU-NEXT: {{ $}}
; AMDGPU-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $vgpr0
; AMDGPU-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $vgpr1
; AMDGPU-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $vgpr2
; AMDGPU-NEXT: [[COPY3:%[0-9]+]]:_(s32) = COPY $vgpr3
; AMDGPU-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<4 x s32>) = G_BUILD_VECTOR [[COPY]](s32), [[COPY1]](s32), [[COPY2]](s32), [[COPY3]](s32)
; AMDGPU-NEXT: [[TRUNC:%[0-9]+]]:_(<4 x s8>) = G_TRUNC [[BUILD_VECTOR]](<4 x s32>)
; AMDGPU-NEXT: [[BITCAST:%[0-9]+]]:_(s32) = G_BITCAST [[TRUNC]](<4 x s8>)
; AMDGPU-NEXT: $vgpr0 = COPY [[BITCAST]](s32)
; AMDGPU-NEXT: SI_RETURN implicit $vgpr0
;
; X86-LABEL: name: bitcast_v4b8_to_b32
; X86: bb.1 (%ir-block.0):
; X86-NEXT: liveins: $xmm0
; X86-NEXT: {{ $}}
; X86-NEXT: [[COPY:%[0-9]+]]:_(<16 x s8>) = COPY $xmm0
; X86-NEXT: [[UV:%[0-9]+]]:_(<4 x s8>), [[UV1:%[0-9]+]]:_(<4 x s8>), [[UV2:%[0-9]+]]:_(<4 x s8>), [[UV3:%[0-9]+]]:_(<4 x s8>) = G_UNMERGE_VALUES [[COPY]](<16 x s8>)
; X86-NEXT: [[BITCAST:%[0-9]+]]:_(s32) = G_BITCAST [[UV]](<4 x s8>)
; X86-NEXT: $eax = COPY [[BITCAST]](s32)
; X86-NEXT: RET 0, implicit $eax
%r = bitcast <4 x b8> %v to b32
ret b32 %r
}
; Byte to float (different LLT in extended mode, same in default mode).
; All in-tree backends run in default mode, so this collapses to a copy.
define float @bitcast_b32_to_float(b32 %b) {
; AARCH64-LABEL: name: bitcast_b32_to_float
; AARCH64: bb.1 (%ir-block.0):
; AARCH64-NEXT: liveins: $w0
; AARCH64-NEXT: {{ $}}
; AARCH64-NEXT: [[COPY:%[0-9]+]]:_(i32) = COPY $w0
; AARCH64-NEXT: [[BITCAST:%[0-9]+]]:_(f32) = G_BITCAST [[COPY]](i32)
; AARCH64-NEXT: $s0 = COPY [[BITCAST]](f32)
; AARCH64-NEXT: RET_ReallyLR implicit $s0
;
; AMDGPU-LABEL: name: bitcast_b32_to_float
; AMDGPU: bb.1 (%ir-block.0):
; AMDGPU-NEXT: liveins: $vgpr0
; AMDGPU-NEXT: {{ $}}
; AMDGPU-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $vgpr0
; AMDGPU-NEXT: $vgpr0 = COPY [[COPY]](s32)
; AMDGPU-NEXT: SI_RETURN implicit $vgpr0
;
; X86-LABEL: name: bitcast_b32_to_float
; X86: bb.1 (%ir-block.0):
; X86-NEXT: liveins: $edi
; X86-NEXT: {{ $}}
; X86-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $edi
; X86-NEXT: $xmm0 = COPY [[COPY]](s32)
; X86-NEXT: RET 0, implicit $xmm0
%r = bitcast b32 %b to float
ret float %r
}
; Pointer (p0) to b64 - lowers to G_PTRTOINT.
define b64 @bitcast_p0_to_b64(ptr %p) {
; AARCH64-LABEL: name: bitcast_p0_to_b64
; AARCH64: bb.1 (%ir-block.0):
; AARCH64-NEXT: liveins: $x0
; AARCH64-NEXT: {{ $}}
; AARCH64-NEXT: [[COPY:%[0-9]+]]:_(p0) = COPY $x0
; AARCH64-NEXT: [[PTRTOINT:%[0-9]+]]:_(i64) = G_PTRTOINT [[COPY]](p0)
; AARCH64-NEXT: $x0 = COPY [[PTRTOINT]](i64)
; AARCH64-NEXT: RET_ReallyLR implicit $x0
;
; AMDGPU-LABEL: name: bitcast_p0_to_b64
; AMDGPU: bb.1 (%ir-block.0):
; AMDGPU-NEXT: liveins: $vgpr0, $vgpr1
; AMDGPU-NEXT: {{ $}}
; AMDGPU-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $vgpr0
; AMDGPU-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $vgpr1
; AMDGPU-NEXT: [[MV:%[0-9]+]]:_(p0) = G_MERGE_VALUES [[COPY]](s32), [[COPY1]](s32)
; AMDGPU-NEXT: [[PTRTOINT:%[0-9]+]]:_(s64) = G_PTRTOINT [[MV]](p0)
; AMDGPU-NEXT: [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[PTRTOINT]](s64)
; AMDGPU-NEXT: $vgpr0 = COPY [[UV]](s32)
; AMDGPU-NEXT: $vgpr1 = COPY [[UV1]](s32)
; AMDGPU-NEXT: SI_RETURN implicit $vgpr0, implicit $vgpr1
;
; X86-LABEL: name: bitcast_p0_to_b64
; X86: bb.1 (%ir-block.0):
; X86-NEXT: liveins: $rdi
; X86-NEXT: {{ $}}
; X86-NEXT: [[COPY:%[0-9]+]]:_(p0) = COPY $rdi
; X86-NEXT: [[PTRTOINT:%[0-9]+]]:_(s64) = G_PTRTOINT [[COPY]](p0)
; X86-NEXT: $rax = COPY [[PTRTOINT]](s64)
; X86-NEXT: RET 0, implicit $rax
%r = bitcast ptr %p to b64
ret b64 %r
}
; Inverse: b64 to a pointer - G_INTTOPTR.
define ptr @bitcast_b64_to_p0(b64 %b) {
; AARCH64-LABEL: name: bitcast_b64_to_p0
; AARCH64: bb.1 (%ir-block.0):
; AARCH64-NEXT: liveins: $x0
; AARCH64-NEXT: {{ $}}
; AARCH64-NEXT: [[COPY:%[0-9]+]]:_(i64) = COPY $x0
; AARCH64-NEXT: [[INTTOPTR:%[0-9]+]]:_(p0) = G_INTTOPTR [[COPY]](i64)
; AARCH64-NEXT: $x0 = COPY [[INTTOPTR]](p0)
; AARCH64-NEXT: RET_ReallyLR implicit $x0
;
; AMDGPU-LABEL: name: bitcast_b64_to_p0
; AMDGPU: bb.1 (%ir-block.0):
; AMDGPU-NEXT: liveins: $vgpr0, $vgpr1
; AMDGPU-NEXT: {{ $}}
; AMDGPU-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $vgpr0
; AMDGPU-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $vgpr1
; AMDGPU-NEXT: [[MV:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY]](s32), [[COPY1]](s32)
; AMDGPU-NEXT: [[INTTOPTR:%[0-9]+]]:_(p0) = G_INTTOPTR [[MV]](s64)
; AMDGPU-NEXT: [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[INTTOPTR]](p0)
; AMDGPU-NEXT: $vgpr0 = COPY [[UV]](s32)
; AMDGPU-NEXT: $vgpr1 = COPY [[UV1]](s32)
; AMDGPU-NEXT: SI_RETURN implicit $vgpr0, implicit $vgpr1
;
; X86-LABEL: name: bitcast_b64_to_p0
; X86: bb.1 (%ir-block.0):
; X86-NEXT: liveins: $rdi
; X86-NEXT: {{ $}}
; X86-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $rdi
; X86-NEXT: [[INTTOPTR:%[0-9]+]]:_(p0) = G_INTTOPTR [[COPY]](s64)
; X86-NEXT: $rax = COPY [[INTTOPTR]](p0)
; X86-NEXT: RET 0, implicit $rax
%r = bitcast b64 %b to ptr
ret ptr %r
}
;;
;; The "bytecast" surface: bitcast is the only IR cast that may produce or
;; consume a byte type. The cases below correspond to LangRef's
;; "If `value` is of the byte type" subsection.
;;
; byte -> integer scalar, same width: same LLT, no instruction emitted.
define i32 @bytecast_b32_to_i32(b32 %b) {
; AARCH64-LABEL: name: bytecast_b32_to_i32
; AARCH64: bb.1 (%ir-block.0):
; AARCH64-NEXT: liveins: $w0
; AARCH64-NEXT: {{ $}}
; AARCH64-NEXT: [[COPY:%[0-9]+]]:_(i32) = COPY $w0
; AARCH64-NEXT: $w0 = COPY [[COPY]](i32)
; AARCH64-NEXT: RET_ReallyLR implicit $w0
;
; AMDGPU-LABEL: name: bytecast_b32_to_i32
; AMDGPU: bb.1 (%ir-block.0):
; AMDGPU-NEXT: liveins: $vgpr0
; AMDGPU-NEXT: {{ $}}
; AMDGPU-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $vgpr0
; AMDGPU-NEXT: $vgpr0 = COPY [[COPY]](s32)
; AMDGPU-NEXT: SI_RETURN implicit $vgpr0
;
; X86-LABEL: name: bytecast_b32_to_i32
; X86: bb.1 (%ir-block.0):
; X86-NEXT: liveins: $edi
; X86-NEXT: {{ $}}
; X86-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $edi
; X86-NEXT: $eax = COPY [[COPY]](s32)
; X86-NEXT: RET 0, implicit $eax
%r = bitcast b32 %b to i32
ret i32 %r
}
; integer -> byte, same width: same LLT, no instruction emitted.
define b32 @bytecast_i32_to_b32(i32 %i) {
; AARCH64-LABEL: name: bytecast_i32_to_b32
; AARCH64: bb.1 (%ir-block.0):
; AARCH64-NEXT: liveins: $w0
; AARCH64-NEXT: {{ $}}
; AARCH64-NEXT: [[COPY:%[0-9]+]]:_(i32) = COPY $w0
; AARCH64-NEXT: $w0 = COPY [[COPY]](i32)
; AARCH64-NEXT: RET_ReallyLR implicit $w0
;
; AMDGPU-LABEL: name: bytecast_i32_to_b32
; AMDGPU: bb.1 (%ir-block.0):
; AMDGPU-NEXT: liveins: $vgpr0
; AMDGPU-NEXT: {{ $}}
; AMDGPU-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $vgpr0
; AMDGPU-NEXT: $vgpr0 = COPY [[COPY]](s32)
; AMDGPU-NEXT: SI_RETURN implicit $vgpr0
;
; X86-LABEL: name: bytecast_i32_to_b32
; X86: bb.1 (%ir-block.0):
; X86-NEXT: liveins: $edi
; X86-NEXT: {{ $}}
; X86-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $edi
; X86-NEXT: $eax = COPY [[COPY]](s32)
; X86-NEXT: RET 0, implicit $eax
%r = bitcast i32 %i to b32
ret b32 %r
}
; byte vector -> byte vector of identical layout: copy.
define <4 x b8> @bytecast_v4b8_to_v4b8(<4 x b8> %v) {
; AARCH64-LABEL: name: bytecast_v4b8_to_v4b8
; AARCH64: bb.1 (%ir-block.0):
; AARCH64-NEXT: liveins: $d0
; AARCH64-NEXT: {{ $}}
; AARCH64-NEXT: [[COPY:%[0-9]+]]:_(<4 x i16>) = COPY $d0
; AARCH64-NEXT: [[TRUNC:%[0-9]+]]:_(<4 x i8>) = G_TRUNC [[COPY]](<4 x i16>)
; AARCH64-NEXT: [[ANYEXT:%[0-9]+]]:_(<4 x i16>) = G_ANYEXT [[TRUNC]](<4 x i8>)
; AARCH64-NEXT: $d0 = COPY [[ANYEXT]](<4 x i16>)
; AARCH64-NEXT: RET_ReallyLR implicit $d0
;
; AMDGPU-LABEL: name: bytecast_v4b8_to_v4b8
; AMDGPU: bb.1 (%ir-block.0):
; AMDGPU-NEXT: liveins: $vgpr0, $vgpr1, $vgpr2, $vgpr3
; AMDGPU-NEXT: {{ $}}
; AMDGPU-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $vgpr0
; AMDGPU-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $vgpr1
; AMDGPU-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $vgpr2
; AMDGPU-NEXT: [[COPY3:%[0-9]+]]:_(s32) = COPY $vgpr3
; AMDGPU-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<4 x s32>) = G_BUILD_VECTOR [[COPY]](s32), [[COPY1]](s32), [[COPY2]](s32), [[COPY3]](s32)
; AMDGPU-NEXT: [[TRUNC:%[0-9]+]]:_(<4 x s8>) = G_TRUNC [[BUILD_VECTOR]](<4 x s32>)
; AMDGPU-NEXT: [[UV:%[0-9]+]]:_(s8), [[UV1:%[0-9]+]]:_(s8), [[UV2:%[0-9]+]]:_(s8), [[UV3:%[0-9]+]]:_(s8) = G_UNMERGE_VALUES [[TRUNC]](<4 x s8>)
; AMDGPU-NEXT: [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[UV]](s8)
; AMDGPU-NEXT: [[ANYEXT1:%[0-9]+]]:_(s32) = G_ANYEXT [[UV1]](s8)
; AMDGPU-NEXT: [[ANYEXT2:%[0-9]+]]:_(s32) = G_ANYEXT [[UV2]](s8)
; AMDGPU-NEXT: [[ANYEXT3:%[0-9]+]]:_(s32) = G_ANYEXT [[UV3]](s8)
; AMDGPU-NEXT: $vgpr0 = COPY [[ANYEXT]](s32)
; AMDGPU-NEXT: $vgpr1 = COPY [[ANYEXT1]](s32)
; AMDGPU-NEXT: $vgpr2 = COPY [[ANYEXT2]](s32)
; AMDGPU-NEXT: $vgpr3 = COPY [[ANYEXT3]](s32)
; AMDGPU-NEXT: SI_RETURN implicit $vgpr0, implicit $vgpr1, implicit $vgpr2, implicit $vgpr3
;
; X86-LABEL: name: bytecast_v4b8_to_v4b8
; X86: bb.1 (%ir-block.0):
; X86-NEXT: liveins: $xmm0
; X86-NEXT: {{ $}}
; X86-NEXT: [[COPY:%[0-9]+]]:_(<16 x s8>) = COPY $xmm0
; X86-NEXT: [[UV:%[0-9]+]]:_(<4 x s8>), [[UV1:%[0-9]+]]:_(<4 x s8>), [[UV2:%[0-9]+]]:_(<4 x s8>), [[UV3:%[0-9]+]]:_(<4 x s8>) = G_UNMERGE_VALUES [[COPY]](<16 x s8>)
; X86-NEXT: [[UV4:%[0-9]+]]:_(s8), [[UV5:%[0-9]+]]:_(s8), [[UV6:%[0-9]+]]:_(s8), [[UV7:%[0-9]+]]:_(s8) = G_UNMERGE_VALUES [[UV]](<4 x s8>)
; X86-NEXT: [[DEF:%[0-9]+]]:_(s8) = G_IMPLICIT_DEF
; X86-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<16 x s8>) = G_BUILD_VECTOR [[UV4]](s8), [[UV5]](s8), [[UV6]](s8), [[UV7]](s8), [[DEF]](s8), [[DEF]](s8), [[DEF]](s8), [[DEF]](s8), [[DEF]](s8), [[DEF]](s8), [[DEF]](s8), [[DEF]](s8), [[DEF]](s8), [[DEF]](s8), [[DEF]](s8), [[DEF]](s8)
; X86-NEXT: $xmm0 = COPY [[BUILD_VECTOR]](<16 x s8>)
; X86-NEXT: RET 0, implicit $xmm0
%r = bitcast <4 x b8> %v to <4 x b8>
ret <4 x b8> %r
}
; byte -> half (16-bit float).
define half @bytecast_b16_to_half(b16 %b) {
; AARCH64-LABEL: name: bytecast_b16_to_half
; AARCH64: bb.1 (%ir-block.0):
; AARCH64-NEXT: liveins: $w0
; AARCH64-NEXT: {{ $}}
; AARCH64-NEXT: [[COPY:%[0-9]+]]:_(i32) = COPY $w0
; AARCH64-NEXT: [[TRUNC:%[0-9]+]]:_(i16) = G_TRUNC [[COPY]](i32)
; AARCH64-NEXT: [[BITCAST:%[0-9]+]]:_(f16) = G_BITCAST [[TRUNC]](i16)
; AARCH64-NEXT: $h0 = COPY [[BITCAST]](f16)
; AARCH64-NEXT: RET_ReallyLR implicit $h0
;
; AMDGPU-LABEL: name: bytecast_b16_to_half
; AMDGPU: bb.1 (%ir-block.0):
; AMDGPU-NEXT: liveins: $vgpr0
; AMDGPU-NEXT: {{ $}}
; AMDGPU-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $vgpr0
; AMDGPU-NEXT: [[TRUNC:%[0-9]+]]:_(s16) = G_TRUNC [[COPY]](s32)
; AMDGPU-NEXT: [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[TRUNC]](s16)
; AMDGPU-NEXT: $vgpr0 = COPY [[ANYEXT]](s32)
; AMDGPU-NEXT: SI_RETURN implicit $vgpr0
;
; X86-LABEL: name: bytecast_b16_to_half
; X86: bb.1 (%ir-block.0):
; X86-NEXT: liveins: $edi
; X86-NEXT: {{ $}}
; X86-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $edi
; X86-NEXT: [[TRUNC:%[0-9]+]]:_(s16) = G_TRUNC [[COPY]](s32)
; X86-NEXT: $xmm0 = COPY [[TRUNC]](s16)
; X86-NEXT: RET 0, implicit $xmm0
%r = bitcast b16 %b to half
ret half %r
}

View file

@ -16,6 +16,7 @@ entry:
; VSX: addis
; VSX: lfs
; VSX: fcmpu
; SPE: lwz
; SPE: efscmpeq
br i1 %cmp, label %if.then, label %if.end
@ -39,6 +40,7 @@ entry:
; VSX: addis
; VSX: lfs
; VSX: fcmpu
; SPE: lwz
; SPE: efscmpeq
br i1 %cmp, label %if.then, label %if.end
@ -62,6 +64,7 @@ entry:
; VSX: addis
; VSX: lfs
; VSX: fcmpu
; SPE: lwz
; SPE: efscmpeq
br i1 %cmp, label %if.then, label %if.end
@ -85,6 +88,7 @@ entry:
; VSX: addis
; VSX: lfd
; VSX: xscmpudp
; SPE: evlddx
; SPE: efdcmpeq
br i1 %cmp, label %if.then, label %if.end
@ -108,6 +112,7 @@ entry:
; VSX: addis
; VSX: lfd
; VSX: xscmpudp
; SPE: evlddx
; SPE: efdcmpeq
br i1 %cmp, label %if.then, label %if.end
@ -131,6 +136,7 @@ entry:
; VSX: addis
; VSX: lfd
; VSX: xscmpudp
; SPE: evlddx
; SPE: efdcmpeq
br i1 %cmp, label %if.then, label %if.end