| ; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 5 |
| ; RUN: llc -mtriple=amdgpu8.03 -O0 -stop-after=irtranslator -global-isel %s -o - 2>&1 | FileCheck %s |
| |
| ; This file checks that the translation from llvm IR to generic |
| ; MachineInstr is correct. |
| |
| ; Tests for add. |
| define void @addi32(i32 %arg1, i32 %arg2) { |
| ; CHECK-LABEL: name: addi32 |
| ; CHECK: bb.1 (%ir-block.0): |
| ; CHECK-NEXT: liveins: $vgpr0, $vgpr1 |
| ; CHECK-NEXT: {{ $}} |
| ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(i32) = COPY $vgpr0 |
| ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(i32) = COPY $vgpr1 |
| ; CHECK-NEXT: [[DEF:%[0-9]+]]:_(p1) = G_IMPLICIT_DEF |
| ; CHECK-NEXT: [[ADD:%[0-9]+]]:_(i32) = G_ADD [[COPY]], [[COPY1]] |
| ; CHECK-NEXT: G_STORE [[ADD]](i32), [[DEF]](p1) :: (store (i32) into `ptr addrspace(1) poison`, addrspace 1) |
| ; CHECK-NEXT: SI_RETURN |
| %res = add i32 %arg1, %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]+]]:_(i32) = COPY $vgpr0 |
| ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(i32) = COPY $vgpr1 |
| ; CHECK-NEXT: [[MV:%[0-9]+]]:_(p1) = G_MERGE_VALUES [[COPY]](i32), [[COPY1]](i32) |
| ; CHECK-NEXT: [[C:%[0-9]+]]:_(i64) = G_CONSTANT i64 42 |
| ; CHECK-NEXT: G_STORE [[C]](i64), [[MV]](p1) :: (store (i64) 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]+]]:_(i32) = COPY $vgpr0 |
| ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(i32) = COPY $vgpr1 |
| ; CHECK-NEXT: [[MV:%[0-9]+]]:_(i64) = G_MERGE_VALUES [[COPY]](i32), [[COPY1]](i32) |
| ; CHECK-NEXT: [[C:%[0-9]+]]:_(i64) = G_CONSTANT i64 0 |
| ; CHECK-NEXT: [[INTTOPTR:%[0-9]+]]:_(p1) = G_INTTOPTR [[MV]](i64) |
| ; CHECK-NEXT: G_STORE [[C]](i64), [[INTTOPTR]](p1) :: (store (i64) 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]+]]:_(i32) = COPY $vgpr0 |
| ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(i32) = COPY $vgpr1 |
| ; CHECK-NEXT: [[MV:%[0-9]+]]:_(p1) = G_MERGE_VALUES [[COPY]](i32), [[COPY1]](i32) |
| ; CHECK-NEXT: [[DEF:%[0-9]+]]:_(p0) = G_IMPLICIT_DEF |
| ; CHECK-NEXT: [[PTRTOINT:%[0-9]+]]:_(i64) = G_PTRTOINT [[MV]](p1) |
| ; CHECK-NEXT: G_STORE [[PTRTOINT]](i64), [[DEF]](p0) :: (store (i64) 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]+]]:_(i32) = COPY $vgpr0 |
| ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(i32) = COPY $vgpr1 |
| ; CHECK-NEXT: [[MV:%[0-9]+]]:_(i64) = G_MERGE_VALUES [[COPY]](i32), [[COPY1]](i32) |
| ; CHECK-NEXT: [[COPY2:%[0-9]+]]:_(i32) = COPY $vgpr2 |
| ; CHECK-NEXT: [[COPY3:%[0-9]+]]:_(i32) = COPY $vgpr3 |
| ; CHECK-NEXT: [[MV1:%[0-9]+]]:_(p1) = G_MERGE_VALUES [[COPY2]](i32), [[COPY3]](i32) |
| ; CHECK-NEXT: G_STORE [[MV]](i64), [[MV1]](p1) :: (store (i64) 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]+]]:_(i32) = COPY $vgpr0 |
| ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(i32) = COPY $vgpr1 |
| ; CHECK-NEXT: [[MV:%[0-9]+]]:_(i64) = G_MERGE_VALUES [[COPY]](i32), [[COPY1]](i32) |
| ; CHECK-NEXT: [[COPY2:%[0-9]+]]:_(i32) = COPY $vgpr2 |
| ; CHECK-NEXT: [[COPY3:%[0-9]+]]:_(i32) = COPY $vgpr3 |
| ; CHECK-NEXT: [[MV1:%[0-9]+]]:_(p1) = G_MERGE_VALUES [[COPY2]](i32), [[COPY3]](i32) |
| ; CHECK-NEXT: G_STORE [[MV]](i64), [[MV1]](p1) :: (store (i64) 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]+]]:_(i32) = COPY $vgpr0 |
| ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(i32) = COPY $vgpr1 |
| ; CHECK-NEXT: [[MV:%[0-9]+]]:_(i64) = G_MERGE_VALUES [[COPY]](i32), [[COPY1]](i32) |
| ; CHECK-NEXT: [[COPY2:%[0-9]+]]:_(i32) = COPY $vgpr2 |
| ; CHECK-NEXT: [[COPY3:%[0-9]+]]:_(i32) = COPY $vgpr3 |
| ; CHECK-NEXT: [[MV1:%[0-9]+]]:_(p1) = G_MERGE_VALUES [[COPY2]](i32), [[COPY3]](i32) |
| ; CHECK-NEXT: [[BITCAST:%[0-9]+]]:_(f64) = G_BITCAST [[MV]](i64) |
| ; CHECK-NEXT: G_STORE [[BITCAST]](f64), [[MV1]](p1) :: (store (f64) 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 i16>) = COPY $vgpr0 |
| ; CHECK-NEXT: [[DEF:%[0-9]+]]:_(p1) = G_IMPLICIT_DEF |
| ; CHECK-NEXT: [[BITCAST:%[0-9]+]]:_(i32) = G_BITCAST [[COPY]](<2 x i16>) |
| ; CHECK-NEXT: G_STORE [[BITCAST]](i32), [[DEF]](p1) :: (store (i32) 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]+]]:_(i32) = COPY $vgpr0 |
| ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(i32) = COPY $vgpr1 |
| ; CHECK-NEXT: [[MV:%[0-9]+]]:_(p1) = G_MERGE_VALUES [[COPY]](i32), [[COPY1]](i32) |
| ; CHECK-NEXT: [[C:%[0-9]+]]:_(i8) = G_CONSTANT i8 1 |
| ; CHECK-NEXT: [[C1:%[0-9]+]]:_(i8) = G_CONSTANT i8 2 |
| ; CHECK-NEXT: [[C2:%[0-9]+]]:_(i8) = G_CONSTANT i8 3 |
| ; CHECK-NEXT: [[C3:%[0-9]+]]:_(i8) = G_CONSTANT i8 4 |
| ; CHECK-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<4 x i8>) = G_BUILD_VECTOR [[C]](i8), [[C1]](i8), [[C2]](i8), [[C3]](i8) |
| ; CHECK-NEXT: G_STORE [[BUILD_VECTOR]](<4 x i8>), [[MV]](p1) :: (store (<4 x i8>) 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]+]]:_(i32) = COPY $vgpr0 |
| ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(i32) = COPY $vgpr1 |
| ; CHECK-NEXT: [[MV:%[0-9]+]]:_(p1) = G_MERGE_VALUES [[COPY]](i32), [[COPY1]](i32) |
| ; CHECK-NEXT: [[LOAD:%[0-9]+]]:_(i64) = G_LOAD [[MV]](p1) :: (load (i64) from %ir.p, addrspace 1) |
| ; CHECK-NEXT: [[UV:%[0-9]+]]:_(i32), [[UV1:%[0-9]+]]:_(i32) = G_UNMERGE_VALUES [[LOAD]](i64) |
| ; CHECK-NEXT: $vgpr0 = COPY [[UV]](i32) |
| ; CHECK-NEXT: $vgpr1 = COPY [[UV1]](i32) |
| ; CHECK-NEXT: SI_RETURN implicit $vgpr0, implicit $vgpr1 |
| %b = load b64, ptr addrspace(1) %p |
| ret b64 %b |
| } |