llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
29.24k stars 12.07k forks source link

No efficient way to convert between fixed and vscale vectors with asserted vscale_range. #56431

Open zvookin opened 2 years ago

zvookin commented 2 years ago

LLVM has fixed and vscale vectors. Casting between them is generally not allowed. Use of llvm.vector.insert.* and llvm.vector.extract.* should be a way to accomplish a zero cost conversion if the hardware size is constrained to a specific value. The function attribute `vscale_range is the way to specify a constraint on the vector hardware width being compiled for. This is very unreliable.

Targeting a known vector size on variable vector size CPUs is an important use case for just in time compilation and known hardware situations (e.g. writing firmware.) That LLVM cannot compile straight forward fixed length vector code for ARM SVE and RISC V vector is a significant productivity blocker.

A minimal LLVM IR test case and stack trace are provided below. This works if the hardware vector size is asserted via backend specific flags such as -riscv-v-vector-bits-min, -riscv-v-vector-bits-max, -aarch64-sve-vector-bits-min, -aarch64-sve-vector-bits-min. One potential design fix would be to make these fixed width flags into per function attributes or part of the target options somehow.

Command to reproduce the failure:

llc -mtriple riscv64 -mattr=+v -verify-machineinstrs < /tmp/test.ll

Command which illustrates machine specific (global) fixed width flags correct the error:

llc -mtriple riscv64 -mattr=+v -verify-machineinstrs -riscv-v-vector-bits-min=512  < /tmp/test.ll

test.ll input:

declare <vscale x 2 x i8> @llvm.vector.insert.nxv2i8.v16i8(<vscale x 2 x i8> %0, <16 x i8> %1, i64 immarg %2)

define <vscale x 2 x i8>  @test_op_vadd_vv_0(ptr noalias nocapture readnone %in) #1 {
  %1 = getelementptr inbounds i8, ptr %in, i64 0
  %2 = load <16 x i8>, ptr %1, align 16
  %3 = tail call <vscale x 2 x i8> @llvm.vector.insert.nxv2i8.v16i8(<vscale x 2 x i8> undef, <16 x i8> %2, i64 0)
  ret <vscale x 2 x i8> %3
}

attributes #1 = { "vscale_range"="8, 8" "min-legal-vector-width=512" }

Stack trace:

ScalarizeVectorOperand Op #1: t109: nxv2i8 = insert_subvector undef:nxv2i8, t105, Constant:i64<0>

LLVM ERROR: Do not know how to scalarize this operator's operand!

PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.
Stack dump:
0.      Program arguments: llc -mtriple riscv64 -mattr=+v -verify-machineinstrs
1.      Running pass 'Function Pass Manager' on module '<stdin>'.
2.      Running pass 'RISCV DAG->DAG Pattern Instruction Selection' on function '@test_op_vadd_vv_0'
 #0 0x0000561aa50c40c2 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) /usr/local/google/home/zalman/src/llvm-project/llvm/lib/Support/Unix/Signals.inc:573:3
 #1 0x0000561aa50c249c llvm::sys::RunSignalHandlers() /usr/local/google/home/zalman/src/llvm-project/llvm/lib/Support/Signals.cpp:103:20
 #2 0x0000561aa50c2626 SignalHandler(int) /usr/local/google/home/zalman/src/llvm-project/llvm/lib/Support/Unix/Signals.inc:407:1
 #3 0x00007f5284f6d200 __restore_rt (/lib/x86_64-linux-gnu/libpthread.so.0+0x12200)
 #4 0x00007f5284a168a1 raise ./signal/../sysdeps/unix/sysv/linux/raise.c:50:1
 #5 0x00007f5284a00546 abort ./stdlib/abort.c:81:7
 #6 0x0000561aa2995c26 llvm::ConvertUTF8toUTF32Impl(unsigned char const**, unsigned char const*, unsigned int**, unsigned int*, llvm::ConversionFlags, unsigned char) (.cold) /usr/local/google/home/zalman/src/llvm-project/llvm/lib/Support/ConvertUTF.cpp:665:9
 #7 0x0000561aa502ea31 (/usr/local/google/home/zalman/src/llvm-project/llvm/RelDbg64/bin/llc+0x30d7a31)
 #8 0x0000561aa4f924c7 llvm::DAGTypeLegalizer::ScalarizeVectorOperand(llvm::SDNode*, unsigned int) /usr/local/google/home/zalman/src/llvm-project/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp:635:23
 #9 0x0000561aa4f49afa llvm::DAGTypeLegalizer::run() /usr/local/google/home/zalman/src/llvm-project/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.cpp:343:17
#10 0x0000561aa4f4aa79 llvm::SmallVectorTemplateCommon<llvm::SDNode*, void>::begin() /usr/local/google/home/zalman/src/llvm-project/llvm/include/llvm/ADT/SmallVector.h:249:45
#11 0x0000561aa4f4aa79 llvm::SmallVectorTemplateCommon<llvm::SDNode*, void>::end() /usr/local/google/home/zalman/src/llvm-project/llvm/include/llvm/ADT/SmallVector.h:251:32
#12 0x0000561aa4f4aa79 llvm::SmallVector<llvm::SDNode*, 128u>::~SmallVector() /usr/local/google/home/zalman/src/llvm-project/llvm/include/llvm/ADT/SmallVector.h:1192:24
#13 0x0000561aa4f4aa79 llvm::DAGTypeLegalizer::~DAGTypeLegalizer() /usr/local/google/home/zalman/src/llvm-project/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h:30:31
#14 0x0000561aa4f4aa79 llvm::SelectionDAG::LegalizeTypes() /usr/local/google/home/zalman/src/llvm-project/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.cpp:1060:10
#15 0x0000561aa4ed8f6c llvm::TimeRegion::~TimeRegion() /usr/local/google/home/zalman/src/llvm-project/llvm/include/llvm/Support/Timer.h:157:9
#16 0x0000561aa4ed8f6c llvm::NamedRegionTimer::~NamedRegionTimer() /usr/local/google/home/zalman/src/llvm-project/llvm/include/llvm/Support/Timer.h:165:8
#17 0x0000561aa4ed8f6c llvm::SelectionDAGISel::CodeGenAndEmitDAG() /usr/local/google/home/zalman/src/llvm-project/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp:839:3
#18 0x0000561aa4edcf80 llvm::SelectionDAGISel::SelectAllBasicBlocks(llvm::Function const&) /usr/local/google/home/zalman/src/llvm-project/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp:1639:33
#19 0x0000561aa4edeab0 llvm::SelectionDAGISel::runOnMachineFunction(llvm::MachineFunction&) (.part.0) /usr/local/google/home/zalman/src/llvm-project/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp:513:22
#20 0x0000561aa4410abc llvm::MachineFunctionPass::runOnFunction(llvm::Function&) (.part.0) /usr/local/google/home/zalman/src/llvm-project/llvm/lib/CodeGen/MachineFunctionPass.cpp:73:33
#21 0x0000561aa489accc llvm::FPPassManager::runOnFunction(llvm::Function&) /usr/local/google/home/zalman/src/llvm-project/llvm/lib/IR/LegacyPassManager.cpp:1440:7
#22 0x0000561aa489aee1 llvm::ilist_node_base<true>::getNext() const /usr/local/google/home/zalman/src/llvm-project/llvm/include/llvm/ADT/ilist_node_base.h:43:45
#23 0x0000561aa489aee1 llvm::ilist_node_impl<llvm::ilist_detail::node_options<llvm::Function, true, false, void>>::getNext() /usr/local/google/home/zalman/src/llvm-project/llvm/include/llvm/ADT/ilist_node.h:67:66
#24 0x0000561aa489aee1 llvm::ilist_iterator<llvm::ilist_detail::node_options<llvm::Function, true, false, void>, false, false>::operator++() /usr/local/google/home/zalman/src/llvm-project/llvm/include/llvm/ADT/ilist_iterator.h:157:25
#25 0x0000561aa489aee1 llvm::FPPassManager::runOnModule(llvm::Module&) /usr/local/google/home/zalman/src/llvm-project/llvm/lib/IR/LegacyPassManager.cpp:1475:22
#26 0x0000561aa489b70e runOnModule /usr/local/google/home/zalman/src/llvm-project/llvm/lib/IR/LegacyPassManager.cpp:1552:7
#27 0x0000561aa489b70e llvm::legacy::PassManagerImpl::run(llvm::Module&) /usr/local/google/home/zalman/src/llvm-project/llvm/lib/IR/LegacyPassManager.cpp:535:55
#28 0x0000561aa2a58637 compileModule(char**, llvm::LLVMContext&) /usr/local/google/home/zalman/src/llvm-project/llvm/tools/llc/llc.cpp:736:66
#29 0x0000561aa299a976 main /usr/local/google/home/zalman/src/llvm-project/llvm/tools/llc/llc.cpp:417:35
#30 0x00007f5284a017fd __libc_start_main ./csu/../csu/libc-start.c:332:16
#31 0x0000561aa2a50d5a _start (/usr/local/google/home/zalman/src/llvm-project/llvm/RelDbg64/bin/llc+0xaf9d5a)
zvookin commented 2 years ago

Note the test case is for RISC V vector, but the same issue applies to ARM SVE.