diff --git a/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h b/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h --- a/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h @@ -431,6 +431,9 @@ /// Return true if a G_SELECT instruction \p MI has an undef comparison. bool matchUndefSelectCmp(MachineInstr &MI); + /// Return true if a G_{EXTRACT,INSERT}_VECTOR_ELT has an out of range index. + bool matchInsertExtractVecEltOutOfBounds(MachineInstr &MI); + /// Return true if a G_SELECT instruction \p MI has a constant comparison. If /// true, \p OpIdx will store the operand index of the known selected value. bool matchConstantSelectCmp(MachineInstr &MI, unsigned &OpIdx); diff --git a/llvm/include/llvm/Target/GlobalISel/Combine.td b/llvm/include/llvm/Target/GlobalISel/Combine.td --- a/llvm/include/llvm/Target/GlobalISel/Combine.td +++ b/llvm/include/llvm/Target/GlobalISel/Combine.td @@ -264,6 +264,13 @@ [{ return Helper.matchUndefShuffleVectorMask(*${root}); }]), (apply [{ Helper.replaceInstWithUndef(*${root}); }])>; + // Replace an insert/extract element of an out of bounds index with undef. + def insert_extract_vec_elt_out_of_bounds : GICombineRule< + (defs root:$root), + (match (wip_match_opcode G_INSERT_VECTOR_ELT, G_EXTRACT_VECTOR_ELT):$root, + [{ return Helper.matchInsertExtractVecEltOutOfBounds(*${root}); }]), + (apply [{ Helper.replaceInstWithUndef(*${root}); }])>; + // Fold (cond ? x : x) -> x def select_same_val: GICombineRule< (defs root:$root), @@ -921,7 +928,8 @@ propagate_undef_all_ops, propagate_undef_shuffle_mask, erase_undef_store, - unmerge_undef]>; + unmerge_undef, + insert_extract_vec_elt_out_of_bounds]>; def identity_combines : GICombineGroup<[select_same_val, right_identity_zero, binop_same_val, binop_left_to_zero, diff --git a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp --- a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp +++ b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp @@ -2332,6 +2332,19 @@ MRI); } +bool CombinerHelper::matchInsertExtractVecEltOutOfBounds(MachineInstr &MI) { + assert(MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT || + MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT && + "Expected an insert/extract element op"); + LLT VecTy = MRI.getType(MI.getOperand(1).getReg()); + unsigned IdxIdx = + MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT ? 2 : 3; + auto Idx = getIConstantVRegVal(MI.getOperand(IdxIdx).getReg(), MRI); + if (!Idx) + return false; + return Idx->getZExtValue() >= VecTy.getNumElements(); +} + bool CombinerHelper::matchConstantSelectCmp(MachineInstr &MI, unsigned &OpIdx) { GSelect &SelMI = cast(MI); auto Cst = diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/combine-build-vector.mir b/llvm/test/CodeGen/AArch64/GlobalISel/combine-build-vector.mir --- a/llvm/test/CodeGen/AArch64/GlobalISel/combine-build-vector.mir +++ b/llvm/test/CodeGen/AArch64/GlobalISel/combine-build-vector.mir @@ -134,13 +134,8 @@ ; CHECK: liveins: $x0, $x1 ; CHECK-NEXT: {{ $}} ; CHECK-NEXT: %arg1:_(s64) = COPY $x0 - ; CHECK-NEXT: %arg2:_(s64) = COPY $x1 - ; CHECK-NEXT: %zero:_(s32) = G_CONSTANT i32 0 - ; CHECK-NEXT: %two:_(s32) = G_CONSTANT i32 2 - ; CHECK-NEXT: %bv:_(<2 x s64>) = G_BUILD_VECTOR %arg1(s64), %arg2(s64) - ; CHECK-NEXT: %extract:_(s64) = G_EXTRACT_VECTOR_ELT %bv(<2 x s64>), %zero(s32) - ; CHECK-NEXT: %extract2:_(s64) = G_EXTRACT_VECTOR_ELT %bv(<2 x s64>), %two(s32) - ; CHECK-NEXT: $x0 = COPY %extract(s64) + ; CHECK-NEXT: %extract2:_(s64) = G_IMPLICIT_DEF + ; CHECK-NEXT: $x0 = COPY %arg1(s64) ; CHECK-NEXT: $x1 = COPY %extract2(s64) ; CHECK-NEXT: RET_ReallyLR implicit $x0 %arg1:_(s64) = COPY $x0 diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/combine-extract-vec-elt.mir b/llvm/test/CodeGen/AArch64/GlobalISel/combine-extract-vec-elt.mir --- a/llvm/test/CodeGen/AArch64/GlobalISel/combine-extract-vec-elt.mir +++ b/llvm/test/CodeGen/AArch64/GlobalISel/combine-extract-vec-elt.mir @@ -78,11 +78,7 @@ ; CHECK-LABEL: name: extract_from_build_vector_idx_invalid ; CHECK: liveins: $x0, $x1 ; CHECK-NEXT: {{ $}} - ; CHECK-NEXT: %arg1:_(s64) = COPY $x0 - ; CHECK-NEXT: %arg2:_(s64) = COPY $x1 - ; CHECK-NEXT: %idx:_(s32) = G_CONSTANT i32 4 - ; CHECK-NEXT: %bv:_(<2 x s64>) = G_BUILD_VECTOR %arg1(s64), %arg2(s64) - ; CHECK-NEXT: %extract:_(s64) = G_EXTRACT_VECTOR_ELT %bv(<2 x s64>), %idx(s32) + ; CHECK-NEXT: %extract:_(s64) = G_IMPLICIT_DEF ; CHECK-NEXT: $x0 = COPY %extract(s64) ; CHECK-NEXT: RET_ReallyLR implicit $x0 %arg1:_(s64) = COPY $x0 @@ -193,3 +189,27 @@ RET_ReallyLR implicit $x0 ... +--- +name: extract_from_idx_negative +alignment: 4 +liveins: + - { reg: '$x0' } + - { reg: '$x1' } +frameInfo: + maxAlignment: 1 +body: | + bb.1: + liveins: $x0, $x1 + ; CHECK-LABEL: name: extract_from_idx_negative + ; CHECK: liveins: $x0, $x1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %extract:_(s64) = G_IMPLICIT_DEF + ; CHECK-NEXT: $x0 = COPY %extract(s64) + ; CHECK-NEXT: RET_ReallyLR implicit $x0 + %vec:_(<2 x s64>) = COPY $q0 + %idx:_(s32) = G_CONSTANT i32 -2 + %extract:_(s64) = G_EXTRACT_VECTOR_ELT %vec(<2 x s64>), %idx(s32) + $x0 = COPY %extract(s64) + RET_ReallyLR implicit $x0 + +... diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/combine-insert-vec-elt.mir b/llvm/test/CodeGen/AArch64/GlobalISel/combine-insert-vec-elt.mir --- a/llvm/test/CodeGen/AArch64/GlobalISel/combine-insert-vec-elt.mir +++ b/llvm/test/CodeGen/AArch64/GlobalISel/combine-insert-vec-elt.mir @@ -76,14 +76,8 @@ ; CHECK-LABEL: name: test_combine_insert_vec_build_vec_idx_oob ; CHECK: liveins: $w0, $w1, $w2, $w3 ; CHECK-NEXT: {{ $}} - ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $w0 - ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $w1 - ; CHECK-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $w2 - ; CHECK-NEXT: [[COPY3:%[0-9]+]]:_(s32) = COPY $w3 - ; CHECK-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<4 x s32>) = G_BUILD_VECTOR [[COPY]](s32), [[COPY1]](s32), [[COPY2]](s32), [[COPY3]](s32) - ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 4 - ; CHECK-NEXT: [[IVEC:%[0-9]+]]:_(<4 x s32>) = G_INSERT_VECTOR_ELT [[BUILD_VECTOR]], [[COPY]](s32), [[C]](s32) - ; CHECK-NEXT: $q0 = COPY [[IVEC]](<4 x s32>) + ; CHECK-NEXT: [[DEF:%[0-9]+]]:_(<4 x s32>) = G_IMPLICIT_DEF + ; CHECK-NEXT: $q0 = COPY [[DEF]](<4 x s32>) %0:_(s32) = COPY $w0 %1:_(s32) = COPY $w1 %6:_(s32) = COPY $w2 @@ -196,13 +190,6 @@ ; CHECK-LABEL: name: test_combine_negative_idx ; CHECK: liveins: $x0 ; CHECK-NEXT: {{ $}} - ; CHECK-NEXT: [[C:%[0-9]+]]:_(s8) = G_CONSTANT i8 127 - ; CHECK-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<32 x s8>) = G_BUILD_VECTOR [[C]](s8), [[C]](s8), [[C]](s8), [[C]](s8), [[C]](s8), [[C]](s8), [[C]](s8), [[C]](s8), [[C]](s8), [[C]](s8), [[C]](s8), [[C]](s8), [[C]](s8), [[C]](s8), [[C]](s8), [[C]](s8), [[C]](s8), [[C]](s8), [[C]](s8), [[C]](s8), [[C]](s8), [[C]](s8), [[C]](s8), [[C]](s8), [[C]](s8), [[C]](s8), [[C]](s8), [[C]](s8), [[C]](s8), [[C]](s8), [[C]](s8), [[C]](s8) - ; CHECK-NEXT: [[C1:%[0-9]+]]:_(s8) = G_CONSTANT i8 -128 - ; CHECK-NEXT: [[C2:%[0-9]+]]:_(s64) = G_CONSTANT i64 -1 - ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(p0) = COPY $x0 - ; CHECK-NEXT: [[IVEC:%[0-9]+]]:_(<32 x s8>) = G_INSERT_VECTOR_ELT [[BUILD_VECTOR]], [[C1]](s8), [[C2]](s64) - ; CHECK-NEXT: G_STORE [[IVEC]](<32 x s8>), [[COPY]](p0) :: (store (<32 x s8>)) ; CHECK-NEXT: RET_ReallyLR %3:_(s8) = G_CONSTANT i8 127 %2:_(<32 x s8>) = G_BUILD_VECTOR %3(s8), %3(s8), %3(s8), %3(s8), %3(s8), %3(s8), %3(s8), %3(s8), %3(s8), %3(s8), %3(s8), %3(s8), %3(s8), %3(s8), %3(s8), %3(s8), %3(s8), %3(s8), %3(s8), %3(s8), %3(s8), %3(s8), %3(s8), %3(s8), %3(s8), %3(s8), %3(s8), %3(s8), %3(s8), %3(s8), %3(s8), %3(s8)