return false;
}
+ static unsigned getMergeOpcode(LLT OpTy, LLT DestTy) {
+ if (OpTy.isVector() && DestTy.isVector())
+ return TargetOpcode::G_CONCAT_VECTORS;
+
+ if (OpTy.isVector() && !DestTy.isVector())
+ return TargetOpcode::G_BUILD_VECTOR;
+
+ return TargetOpcode::G_MERGE_VALUES;
+ }
+
bool tryCombineMerges(MachineInstr &MI,
SmallVectorImpl<MachineInstr *> &DeadInsts) {
unsigned NumDefs = MI.getNumOperands() - 1;
- unsigned MergingOpcode;
LLT OpTy = MRI.getType(MI.getOperand(NumDefs).getReg());
LLT DestTy = MRI.getType(MI.getOperand(0).getReg());
- if (OpTy.isVector() && DestTy.isVector())
- MergingOpcode = TargetOpcode::G_CONCAT_VECTORS;
- else if (OpTy.isVector() && !DestTy.isVector())
- MergingOpcode = TargetOpcode::G_BUILD_VECTOR;
- else
- MergingOpcode = TargetOpcode::G_MERGE_VALUES;
+ unsigned MergingOpcode = getMergeOpcode(OpTy, DestTy);
MachineInstr *MergeI =
getOpcodeDef(MergingOpcode, MI.getOperand(NumDefs).getReg(), MRI);
return true;
}
+ static bool isMergeLikeOpcode(unsigned Opc) {
+ switch (Opc) {
+ case TargetOpcode::G_MERGE_VALUES:
+ case TargetOpcode::G_BUILD_VECTOR:
+ case TargetOpcode::G_CONCAT_VECTORS:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ bool tryCombineExtract(MachineInstr &MI,
+ SmallVectorImpl<MachineInstr *> &DeadInsts) {
+ assert(MI.getOpcode() == TargetOpcode::G_EXTRACT);
+
+ // Try to use the source registers from a G_MERGE_VALUES
+ //
+ // %2 = G_MERGE_VALUES %0, %1
+ // %3 = G_EXTRACT %2, N
+ // =>
+ //
+ // for N < %2.getSizeInBits() / 2
+ // %3 = G_EXTRACT %0, N
+ //
+ // for N >= %2.getSizeInBits() / 2
+ // %3 = G_EXTRACT %1, (N - %0.getSizeInBits()
+
+ unsigned Src = lookThroughCopyInstrs(MI.getOperand(1).getReg());
+ MachineInstr *MergeI = MRI.getVRegDef(Src);
+ if (!MergeI || !isMergeLikeOpcode(MergeI->getOpcode()))
+ return false;
+
+ LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
+ LLT SrcTy = MRI.getType(Src);
+
+ // TODO: Do we need to check if the resulting extract is supported?
+ unsigned ExtractDstSize = DstTy.getSizeInBits();
+ unsigned Offset = MI.getOperand(2).getImm();
+ unsigned NumMergeSrcs = MergeI->getNumOperands() - 1;
+ unsigned MergeSrcSize = SrcTy.getSizeInBits() / NumMergeSrcs;
+ unsigned MergeSrcIdx = Offset / MergeSrcSize;
+
+ // Compute the offset of the last bit the extract needs.
+ unsigned EndMergeSrcIdx = (Offset + ExtractDstSize - 1) / MergeSrcSize;
+
+ // Can't handle the case where the extract spans multiple inputs.
+ if (MergeSrcIdx != EndMergeSrcIdx)
+ return false;
+
+ // TODO: We could modify MI in place in most cases.
+ Builder.setInstr(MI);
+ Builder.buildExtract(
+ MI.getOperand(0).getReg(),
+ MergeI->getOperand(MergeSrcIdx + 1).getReg(),
+ Offset - MergeSrcIdx * MergeSrcSize);
+ markInstAndDefDead(MI, *MergeI, DeadInsts);
+ return true;
+ }
+
/// Try to combine away MI.
/// Returns true if it combined away the MI.
/// Adds instructions that are dead as a result of the combine
return tryCombineSExt(MI, DeadInsts);
case TargetOpcode::G_UNMERGE_VALUES:
return tryCombineMerges(MI, DeadInsts);
+ case TargetOpcode::G_EXTRACT:
+ return tryCombineExtract(MI, DeadInsts);
case TargetOpcode::G_TRUNC: {
bool Changed = false;
for (auto &Use : MRI.use_instructions(MI.getOperand(0).getReg()))
}
private:
+
+ static unsigned getArtifactSrcReg(const MachineInstr &MI) {
+ switch (MI.getOpcode()) {
+ case TargetOpcode::COPY:
+ case TargetOpcode::G_TRUNC:
+ case TargetOpcode::G_ZEXT:
+ case TargetOpcode::G_ANYEXT:
+ case TargetOpcode::G_SEXT:
+ case TargetOpcode::G_UNMERGE_VALUES:
+ return MI.getOperand(MI.getNumOperands() - 1).getReg();
+ case TargetOpcode::G_EXTRACT:
+ return MI.getOperand(1).getReg();
+ default:
+ llvm_unreachable("Not a legalization artifact happen");
+ }
+ }
+
/// Mark MI as dead. If a def of one of MI's operands, DefMI, would also be
/// dead due to MI being killed, then mark DefMI as dead too.
/// Some of the combines (extends(trunc)), try to walk through redundant
// and as a result, %3, %2, %1 are dead.
MachineInstr *PrevMI = &MI;
while (PrevMI != &DefMI) {
- unsigned PrevRegSrc =
- PrevMI->getOperand(PrevMI->getNumOperands() - 1).getReg();
+ unsigned PrevRegSrc = getArtifactSrcReg(*PrevMI);
+
MachineInstr *TmpDef = MRI.getVRegDef(PrevRegSrc);
if (MRI.hasOneUse(PrevRegSrc)) {
if (TmpDef != &DefMI) {
--- /dev/null
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
+# RUN: llc -O0 -mtriple=amdgcn-mesa-mesa3d -mcpu=tahiti -run-pass=legalizer -global-isel-abort=0 %s -o - | FileCheck %s
+
+---
+name: extract_s32_merge_s64_s32_s32_offset0
+
+body: |
+ bb.0:
+ ; CHECK-LABEL: name: extract_s32_merge_s64_s32_s32_offset0
+ ; CHECK: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+ ; CHECK: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 1
+ ; CHECK: [[COPY:%[0-9]+]]:_(s32) = COPY [[C]](s32)
+ ; CHECK: $vgpr0 = COPY [[COPY]](s32)
+ %0:_(s32) = G_CONSTANT i32 0
+ %1:_(s32) = G_CONSTANT i32 1
+ %2:_(s64) = G_MERGE_VALUES %0, %1
+ %3:_(s32) = G_EXTRACT %2, 0
+ $vgpr0 = COPY %3
+...
+
+---
+name: extract_s32_merge_s64_s32_s32_offset32
+
+body: |
+ bb.0:
+ ; CHECK-LABEL: name: extract_s32_merge_s64_s32_s32_offset32
+ ; CHECK: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+ ; CHECK: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 1
+ ; CHECK: [[COPY:%[0-9]+]]:_(s32) = COPY [[C1]](s32)
+ ; CHECK: $vgpr0 = COPY [[COPY]](s32)
+ %0:_(s32) = G_CONSTANT i32 0
+ %1:_(s32) = G_CONSTANT i32 1
+ %2:_(s64) = G_MERGE_VALUES %0, %1
+ %3:_(s32) = G_EXTRACT %2, 32
+ $vgpr0 = COPY %3
+...
+
+---
+name: extract_s64_merge_s128_s64_s64_offset0
+
+body: |
+ bb.0:
+ ; CHECK-LABEL: name: extract_s64_merge_s128_s64_s64_offset0
+ ; CHECK: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 0
+ ; CHECK: [[C1:%[0-9]+]]:_(s64) = G_CONSTANT i64 1
+ ; CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY [[C]](s64)
+ ; CHECK: $vgpr0_vgpr1 = COPY [[COPY]](s64)
+ %0:_(s64) = G_CONSTANT i64 0
+ %1:_(s64) = G_CONSTANT i64 1
+ %2:_(s128) = G_MERGE_VALUES %0, %1
+ %3:_(s64) = G_EXTRACT %2, 0
+ $vgpr0_vgpr1 = COPY %3
+...
+
+---
+name: extract_s64_merge_s128_s64_s64_offset64
+
+body: |
+ bb.0:
+ ; CHECK-LABEL: name: extract_s64_merge_s128_s64_s64_offset64
+ ; CHECK: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 0
+ ; CHECK: [[C1:%[0-9]+]]:_(s64) = G_CONSTANT i64 1
+ ; CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY [[C1]](s64)
+ ; CHECK: $vgpr0_vgpr1 = COPY [[COPY]](s64)
+ %0:_(s64) = G_CONSTANT i64 0
+ %1:_(s64) = G_CONSTANT i64 1
+ %2:_(s128) = G_MERGE_VALUES %0, %1
+ %3:_(s64) = G_EXTRACT %2, 64
+ $vgpr0_vgpr1 = COPY %3
+...
+
+---
+name: extract_s32_merge_s128_s64_s64_offset0
+
+body: |
+ bb.0:
+ ; CHECK-LABEL: name: extract_s32_merge_s128_s64_s64_offset0
+ ; CHECK: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 0
+ ; CHECK: [[C1:%[0-9]+]]:_(s64) = G_CONSTANT i64 1
+ ; CHECK: [[EXTRACT:%[0-9]+]]:_(s32) = G_EXTRACT [[C]](s64), 0
+ ; CHECK: $vgpr0 = COPY [[EXTRACT]](s32)
+ %0:_(s64) = G_CONSTANT i64 0
+ %1:_(s64) = G_CONSTANT i64 1
+ %2:_(s128) = G_MERGE_VALUES %0, %1
+ %3:_(s32) = G_EXTRACT %2, 0
+ $vgpr0 = COPY %3
+...
+
+---
+name: extract_s32_merge_s128_s64_s64_offset32
+
+body: |
+ bb.0:
+ ; CHECK-LABEL: name: extract_s32_merge_s128_s64_s64_offset32
+ ; CHECK: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 0
+ ; CHECK: [[C1:%[0-9]+]]:_(s64) = G_CONSTANT i64 1
+ ; CHECK: [[EXTRACT:%[0-9]+]]:_(s32) = G_EXTRACT [[C]](s64), 32
+ ; CHECK: $vgpr0 = COPY [[EXTRACT]](s32)
+ %0:_(s64) = G_CONSTANT i64 0
+ %1:_(s64) = G_CONSTANT i64 1
+ %2:_(s128) = G_MERGE_VALUES %0, %1
+ %3:_(s32) = G_EXTRACT %2, 32
+ $vgpr0 = COPY %3
+...
+
+---
+name: extract_s32_merge_s128_s64_s64_offset64
+
+body: |
+ bb.0:
+ ; CHECK-LABEL: name: extract_s32_merge_s128_s64_s64_offset64
+ ; CHECK: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 0
+ ; CHECK: [[C1:%[0-9]+]]:_(s64) = G_CONSTANT i64 1
+ ; CHECK: [[EXTRACT:%[0-9]+]]:_(s32) = G_EXTRACT [[C1]](s64), 0
+ ; CHECK: $vgpr0 = COPY [[EXTRACT]](s32)
+ %0:_(s64) = G_CONSTANT i64 0
+ %1:_(s64) = G_CONSTANT i64 1
+ %2:_(s128) = G_MERGE_VALUES %0, %1
+ %3:_(s32) = G_EXTRACT %2, 64
+ $vgpr0 = COPY %3
+...
+
+---
+name: extract_s32_merge_s128_s64_s64_offset96
+
+body: |
+ bb.0:
+ ; CHECK-LABEL: name: extract_s32_merge_s128_s64_s64_offset96
+ ; CHECK: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 0
+ ; CHECK: [[C1:%[0-9]+]]:_(s64) = G_CONSTANT i64 1
+ ; CHECK: [[EXTRACT:%[0-9]+]]:_(s32) = G_EXTRACT [[C1]](s64), 32
+ ; CHECK: $vgpr0 = COPY [[EXTRACT]](s32)
+ %0:_(s64) = G_CONSTANT i64 0
+ %1:_(s64) = G_CONSTANT i64 1
+ %2:_(s128) = G_MERGE_VALUES %0, %1
+ %3:_(s32) = G_EXTRACT %2, 96
+ $vgpr0 = COPY %3
+...
+
+# Destination size fits, but is skewed from the start of the register.
+---
+name: extract_s16_merge_s128_s64_s64_offset18
+
+body: |
+ bb.0:
+ ; CHECK-LABEL: name: extract_s16_merge_s128_s64_s64_offset18
+ ; CHECK: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 0
+ ; CHECK: [[C1:%[0-9]+]]:_(s64) = G_CONSTANT i64 1
+ ; CHECK: [[EXTRACT:%[0-9]+]]:_(s16) = G_EXTRACT [[C]](s64), 18
+ ; CHECK: [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[EXTRACT]](s16)
+ ; CHECK: $vgpr0 = COPY [[ANYEXT]](s32)
+ %0:_(s64) = G_CONSTANT i64 0
+ %1:_(s64) = G_CONSTANT i64 1
+ %2:_(s128) = G_MERGE_VALUES %0, %1
+ %3:_(s16) = G_EXTRACT %2, 18
+ %4:_(s32) = G_ANYEXT %3
+ $vgpr0 = COPY %4
+...
+
+# Destination size fits, but is skewed from the start of the register.
+---
+name: extract_s16_merge_s128_s64_s64_offset82
+
+body: |
+ bb.0:
+ ; CHECK-LABEL: name: extract_s16_merge_s128_s64_s64_offset82
+ ; CHECK: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 0
+ ; CHECK: [[C1:%[0-9]+]]:_(s64) = G_CONSTANT i64 1
+ ; CHECK: [[EXTRACT:%[0-9]+]]:_(s16) = G_EXTRACT [[C1]](s64), 18
+ ; CHECK: [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[EXTRACT]](s16)
+ ; CHECK: $vgpr0 = COPY [[ANYEXT]](s32)
+ %0:_(s64) = G_CONSTANT i64 0
+ %1:_(s64) = G_CONSTANT i64 1
+ %2:_(s128) = G_MERGE_VALUES %0, %1
+ %3:_(s16) = G_EXTRACT %2, 82
+ %4:_(s32) = G_ANYEXT %3
+ $vgpr0 = COPY %4
+...
+
+
+# Can't handle this since it spans two registers
+---
+name: extract_s64_merge_s128_s64_s64_offset32
+
+body: |
+ bb.0:
+ ; CHECK-LABEL: name: extract_s64_merge_s128_s64_s64_offset32
+ ; CHECK: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 0
+ ; CHECK: [[C1:%[0-9]+]]:_(s64) = G_CONSTANT i64 1
+ ; CHECK: [[MV:%[0-9]+]]:_(s128) = G_MERGE_VALUES [[C]](s64), [[C1]](s64)
+ ; CHECK: [[EXTRACT:%[0-9]+]]:_(s64) = G_EXTRACT [[MV]](s128), 32
+ ; CHECK: $vgpr0_vgpr1 = COPY [[EXTRACT]](s64)
+ %0:_(s64) = G_CONSTANT i64 0
+ %1:_(s64) = G_CONSTANT i64 1
+ %2:_(s128) = G_MERGE_VALUES %0, %1
+ %3:_(s64) = G_EXTRACT %2, 32
+ $vgpr0_vgpr1 = COPY %3
+...
+
+
+# Only the last bit spans to another register
+---
+name: extract_s16_merge_s32_s32_offset1
+
+body: |
+ bb.0:
+ ; CHECK-LABEL: name: extract_s16_merge_s32_s32_offset1
+ ; CHECK: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+ ; CHECK: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 1
+ ; CHECK: [[MV:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[C]](s32), [[C1]](s32)
+ ; CHECK: [[EXTRACT:%[0-9]+]]:_(s32) = G_EXTRACT [[MV]](s64), 1
+ ; CHECK: $vgpr0 = COPY [[EXTRACT]](s32)
+ %0:_(s32) = G_CONSTANT i32 0
+ %1:_(s32) = G_CONSTANT i32 1
+ %2:_(s64) = G_MERGE_VALUES %0, %1
+ %3:_(s32) = G_EXTRACT %2, 1
+ $vgpr0 = COPY %3
+...
+
+
+# Test with some merges with 3 operands
+
+---
+name: extract_s32_merge_s96_s32_s32_s32_offset0
+
+body: |
+ bb.0:
+ ; CHECK-LABEL: name: extract_s32_merge_s96_s32_s32_s32_offset0
+ ; CHECK: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+ ; CHECK: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 1
+ ; CHECK: [[C2:%[0-9]+]]:_(s32) = G_CONSTANT i32 1
+ ; CHECK: [[COPY:%[0-9]+]]:_(s32) = COPY [[C]](s32)
+ ; CHECK: $vgpr0 = COPY [[COPY]](s32)
+ %0:_(s32) = G_CONSTANT i32 0
+ %1:_(s32) = G_CONSTANT i32 1
+ %2:_(s32) = G_CONSTANT i32 1
+ %3:_(s96) = G_MERGE_VALUES %0, %1, %2
+ %4:_(s32) = G_EXTRACT %3, 0
+ $vgpr0 = COPY %4
+...
+
+---
+name: extract_s32_merge_s96_s32_s32_s32_offset64
+
+body: |
+ bb.0:
+ ; CHECK-LABEL: name: extract_s32_merge_s96_s32_s32_s32_offset64
+ ; CHECK: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+ ; CHECK: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 1
+ ; CHECK: [[C2:%[0-9]+]]:_(s32) = G_CONSTANT i32 1
+ ; CHECK: [[COPY:%[0-9]+]]:_(s32) = COPY [[C2]](s32)
+ ; CHECK: $vgpr0 = COPY [[COPY]](s32)
+ %0:_(s32) = G_CONSTANT i32 0
+ %1:_(s32) = G_CONSTANT i32 1
+ %2:_(s32) = G_CONSTANT i32 1
+ %3:_(s96) = G_MERGE_VALUES %0, %1, %2
+ %4:_(s32) = G_EXTRACT %3, 64
+ $vgpr0 = COPY %4
+...
+
+---
+name: extract_s64_merge_s96_s32_s32_s32_offset0
+
+body: |
+ bb.0:
+ ; CHECK-LABEL: name: extract_s64_merge_s96_s32_s32_s32_offset0
+ ; CHECK: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+ ; CHECK: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 1
+ ; CHECK: [[C2:%[0-9]+]]:_(s32) = G_CONSTANT i32 1
+ ; CHECK: [[MV:%[0-9]+]]:_(s96) = G_MERGE_VALUES [[C]](s32), [[C1]](s32), [[C2]](s32)
+ ; CHECK: [[EXTRACT:%[0-9]+]]:_(s64) = G_EXTRACT [[MV]](s96), 0
+ ; CHECK: $vgpr0_vgpr1 = COPY [[EXTRACT]](s64)
+ %0:_(s32) = G_CONSTANT i32 0
+ %1:_(s32) = G_CONSTANT i32 1
+ %2:_(s32) = G_CONSTANT i32 1
+ %3:_(s96) = G_MERGE_VALUES %0, %1, %2
+ %4:_(s64) = G_EXTRACT %3, 0
+ $vgpr0_vgpr1 = COPY %4
+...
+
+---
+name: extract_s64_merge_s96_s32_s32_s32_offset32
+
+body: |
+ bb.0:
+ ; CHECK-LABEL: name: extract_s64_merge_s96_s32_s32_s32_offset32
+ ; CHECK: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+ ; CHECK: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 1
+ ; CHECK: [[C2:%[0-9]+]]:_(s32) = G_CONSTANT i32 1
+ ; CHECK: [[MV:%[0-9]+]]:_(s96) = G_MERGE_VALUES [[C]](s32), [[C1]](s32), [[C2]](s32)
+ ; CHECK: [[EXTRACT:%[0-9]+]]:_(s64) = G_EXTRACT [[MV]](s96), 32
+ ; CHECK: $vgpr0_vgpr1 = COPY [[EXTRACT]](s64)
+ %0:_(s32) = G_CONSTANT i32 0
+ %1:_(s32) = G_CONSTANT i32 1
+ %2:_(s32) = G_CONSTANT i32 1
+ %3:_(s96) = G_MERGE_VALUES %0, %1, %2
+ %4:_(s64) = G_EXTRACT %3, 32
+ $vgpr0_vgpr1 = COPY %4
+...
+
+# Test build_vector sources
+---
+name: extract_s64_build_vector_v2s64_s64_s64_offset0
+
+body: |
+ bb.0:
+ ; CHECK-LABEL: name: extract_s64_build_vector_v2s64_s64_s64_offset0
+ ; CHECK: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 0
+ ; CHECK: [[C1:%[0-9]+]]:_(s64) = G_CONSTANT i64 1
+ ; CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY [[C]](s64)
+ ; CHECK: $vgpr0_vgpr1 = COPY [[COPY]](s64)
+ %0:_(s64) = G_CONSTANT i64 0
+ %1:_(s64) = G_CONSTANT i64 1
+ %2:_(<2 x s64>) = G_BUILD_VECTOR %0, %1
+ %3:_(s64) = G_EXTRACT %2, 0
+ $vgpr0_vgpr1 = COPY %3
+...
+
+---
+name: extract_s64_build_vector_v2s64_s64_s64_offset64
+
+body: |
+ bb.0:
+ ; CHECK-LABEL: name: extract_s64_build_vector_v2s64_s64_s64_offset64
+ ; CHECK: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 0
+ ; CHECK: [[C1:%[0-9]+]]:_(s64) = G_CONSTANT i64 1
+ ; CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY [[C1]](s64)
+ ; CHECK: $vgpr0_vgpr1 = COPY [[COPY]](s64)
+ %0:_(s64) = G_CONSTANT i64 0
+ %1:_(s64) = G_CONSTANT i64 1
+ %2:_(<2 x s64>) = G_BUILD_VECTOR %0, %1
+ %3:_(s64) = G_EXTRACT %2, 64
+ $vgpr0_vgpr1 = COPY %3
+...
+
+---
+name: extract_s64_build_vector_v2s64_s64_s64_offset32
+
+body: |
+ bb.0:
+ ; CHECK-LABEL: name: extract_s64_build_vector_v2s64_s64_s64_offset32
+ ; CHECK: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 0
+ ; CHECK: [[C1:%[0-9]+]]:_(s64) = G_CONSTANT i64 1
+ ; CHECK: [[BUILD_VECTOR:%[0-9]+]]:_(<2 x s64>) = G_BUILD_VECTOR [[C]](s64), [[C1]](s64)
+ ; CHECK: [[EXTRACT:%[0-9]+]]:_(s64) = G_EXTRACT [[BUILD_VECTOR]](<2 x s64>), 32
+ ; CHECK: $vgpr0_vgpr1 = COPY [[EXTRACT]](s64)
+ %0:_(s64) = G_CONSTANT i64 0
+ %1:_(s64) = G_CONSTANT i64 1
+ %2:_(<2 x s64>) = G_BUILD_VECTOR %0, %1
+ %3:_(s64) = G_EXTRACT %2, 32
+ $vgpr0_vgpr1 = COPY %3
+...
+
+# Test extracting something smaller than the element size
+---
+name: extract_s32_build_vector_v2s64_s64_s64_offset64
+
+body: |
+ bb.0:
+ ; CHECK-LABEL: name: extract_s32_build_vector_v2s64_s64_s64_offset64
+ ; CHECK: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 0
+ ; CHECK: [[C1:%[0-9]+]]:_(s64) = G_CONSTANT i64 1
+ ; CHECK: [[EXTRACT:%[0-9]+]]:_(s32) = G_EXTRACT [[C1]](s64), 0
+ ; CHECK: $vgpr0 = COPY [[EXTRACT]](s32)
+ %0:_(s64) = G_CONSTANT i64 0
+ %1:_(s64) = G_CONSTANT i64 1
+ %2:_(<2 x s64>) = G_BUILD_VECTOR %0, %1
+ %3:_(s32) = G_EXTRACT %2, 64
+ $vgpr0 = COPY %3
+
+...
+
+# Test concat_vector sources
+---
+name: extract_v2s16_build_vector_v2s64_v2s16_v2s16_offset0
+
+body: |
+ bb.0:
+ liveins: $vgpr0, $vgpr1
+ ; CHECK-LABEL: name: extract_v2s16_build_vector_v2s64_v2s16_v2s16_offset0
+ ; CHECK: [[COPY:%[0-9]+]]:_(<2 x s16>) = COPY $vgpr0
+ ; CHECK: [[COPY1:%[0-9]+]]:_(<2 x s16>) = COPY $vgpr1
+ ; CHECK: [[COPY2:%[0-9]+]]:_(<2 x s16>) = COPY [[COPY]](<2 x s16>)
+ ; CHECK: $vgpr0 = COPY [[COPY2]](<2 x s16>)
+ %0:_(<2 x s16>) = COPY $vgpr0
+ %1:_(<2 x s16>) = COPY $vgpr1
+ %2:_(<4 x s16>) = G_CONCAT_VECTORS %0, %1
+ %3:_(<2 x s16>) = G_EXTRACT %2, 0
+ $vgpr0 = COPY %3
+...
+
+---
+name: extract_v2s16_build_vector_v2s64_v2s16_v2s16_offset32
+
+body: |
+ bb.0:
+ liveins: $vgpr0, $vgpr1
+ ; CHECK-LABEL: name: extract_v2s16_build_vector_v2s64_v2s16_v2s16_offset32
+ ; CHECK: [[COPY:%[0-9]+]]:_(<2 x s16>) = COPY $vgpr0
+ ; CHECK: [[COPY1:%[0-9]+]]:_(<2 x s16>) = COPY $vgpr1
+ ; CHECK: [[COPY2:%[0-9]+]]:_(<2 x s16>) = COPY [[COPY1]](<2 x s16>)
+ ; CHECK: $vgpr0 = COPY [[COPY2]](<2 x s16>)
+ %0:_(<2 x s16>) = COPY $vgpr0
+ %1:_(<2 x s16>) = COPY $vgpr1
+ %2:_(<4 x s16>) = G_CONCAT_VECTORS %0, %1
+ %3:_(<2 x s16>) = G_EXTRACT %2, 32
+ $vgpr0 = COPY %3
+...
+
+# Test extracting only a single element, not a subvector
+---
+name: extract_s16_build_vector_v2s64_v2s16_v2s16_offset32
+
+body: |
+ bb.0:
+ liveins: $vgpr0, $vgpr1
+ ; CHECK-LABEL: name: extract_s16_build_vector_v2s64_v2s16_v2s16_offset32
+ ; CHECK: [[COPY:%[0-9]+]]:_(<2 x s16>) = COPY $vgpr0
+ ; CHECK: [[COPY1:%[0-9]+]]:_(<2 x s16>) = COPY $vgpr1
+ ; CHECK: [[EXTRACT:%[0-9]+]]:_(s16) = G_EXTRACT [[COPY1]](<2 x s16>), 0
+ ; CHECK: [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[EXTRACT]](s16)
+ ; CHECK: $vgpr0 = COPY [[ANYEXT]](s32)
+ %0:_(<2 x s16>) = COPY $vgpr0
+ %1:_(<2 x s16>) = COPY $vgpr1
+ %2:_(<4 x s16>) = G_CONCAT_VECTORS %0, %1
+ %3:_(s16) = G_EXTRACT %2, 32
+ %4:_(s32) = G_ANYEXT %3
+ $vgpr0 = COPY %4
+...
+
+---
+name: extract_s16_build_vector_v2s64_v2s16_v2s16_offset48
+
+body: |
+ bb.0:
+ liveins: $vgpr0, $vgpr1
+ ; CHECK-LABEL: name: extract_s16_build_vector_v2s64_v2s16_v2s16_offset48
+ ; CHECK: [[COPY:%[0-9]+]]:_(<2 x s16>) = COPY $vgpr0
+ ; CHECK: [[COPY1:%[0-9]+]]:_(<2 x s16>) = COPY $vgpr1
+ ; CHECK: [[EXTRACT:%[0-9]+]]:_(s16) = G_EXTRACT [[COPY1]](<2 x s16>), 16
+ ; CHECK: [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[EXTRACT]](s16)
+ ; CHECK: $vgpr0 = COPY [[ANYEXT]](s32)
+ %0:_(<2 x s16>) = COPY $vgpr0
+ %1:_(<2 x s16>) = COPY $vgpr1
+ %2:_(<4 x s16>) = G_CONCAT_VECTORS %0, %1
+ %3:_(s16) = G_EXTRACT %2, 48
+ %4:_(s32) = G_ANYEXT %3
+ $vgpr0 = COPY %4
+...
+
+# Test extracting less than an element
+---
+name: extract_s8_build_vector_v2s64_v2s16_v2s16_offset48
+
+body: |
+ bb.0:
+ liveins: $vgpr0, $vgpr1
+ ; CHECK-LABEL: name: extract_s8_build_vector_v2s64_v2s16_v2s16_offset48
+ ; CHECK: [[COPY:%[0-9]+]]:_(<2 x s16>) = COPY $vgpr0
+ ; CHECK: [[COPY1:%[0-9]+]]:_(<2 x s16>) = COPY $vgpr1
+ ; CHECK: [[EXTRACT:%[0-9]+]]:_(s8) = G_EXTRACT [[COPY1]](<2 x s16>), 16
+ ; CHECK: [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[EXTRACT]](s8)
+ ; CHECK: $vgpr0 = COPY [[ANYEXT]](s32)
+ %0:_(<2 x s16>) = COPY $vgpr0
+ %1:_(<2 x s16>) = COPY $vgpr1
+ %2:_(<4 x s16>) = G_CONCAT_VECTORS %0, %1
+ %3:_(s8) = G_EXTRACT %2, 48
+ %4:_(s32) = G_ANYEXT %3
+ $vgpr0 = COPY %4
+...