Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RISCV] Cannot scavenge register without an emergency spill slot #58027

Closed
HazyFish opened this issue Sep 27, 2022 · 10 comments
Closed

[RISCV] Cannot scavenge register without an emergency spill slot #58027

HazyFish opened this issue Sep 27, 2022 · 10 comments

Comments

@HazyFish
Copy link
Contributor

HazyFish commented Sep 27, 2022

Description

For both RISCV32 and RISCV64, some specific value / range for the index argument of the getelementptr instruction may lead to crash with "Error while trying to spill X__ from class GPR: Cannot scavenge register without an emergency spill slot" when interacting with other instructions.

Reproduction 1

In the following minimal case, the crash only seems to occur when the index argument for getelementptr is exactly 127.

https://godbolt.org/z/seaPGnsY6

Code

define void @f() {
BB:
  %A = alloca <16 x i8>
  %A1 = alloca <16 x i1>
  %L = load <16 x i1>, <16 x i1>* %A1
  %G = getelementptr <16 x i8>, <16 x i8>* %A, i32 127
  %S = select <16 x i1> %L, <16 x i8> zeroinitializer, <16 x i8> <i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1>
  store <16 x i8> %S, <16 x i8>* %G
  ret void
}

Stack Trace

LLVM ERROR: Error while trying to spill X15 from class GPR: Cannot scavenge register without an emergency spill slot!
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.
Stack dump:
0.	Program arguments: ./llvm-project/build-debug/bin/llc -mtriple=riscv64 crash-reports/riscv64/4.1.ll
1.	Running pass 'Function Pass Manager' on module 'crash-reports/riscv64/4.1.ll'.
2.	Running pass 'Prologue/Epilogue Insertion & Frame Finalization' on function '@f'
 #0 0x0000000003adad2a llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) /home/henry/aflplusplus-isel/llvm-project/llvm/lib/Support/Unix/Signals.inc:569:11
 #1 0x0000000003adaedb PrintStackTraceSignalHandler(void*) /home/henry/aflplusplus-isel/llvm-project/llvm/lib/Support/Unix/Signals.inc:636:1
 #2 0x0000000003ad9526 llvm::sys::RunSignalHandlers() /home/henry/aflplusplus-isel/llvm-project/llvm/lib/Support/Signals.cpp:103:5
 #3 0x0000000003adb605 SignalHandler(int) /home/henry/aflplusplus-isel/llvm-project/llvm/lib/Support/Unix/Signals.inc:407:1
 #4 0x00007f7ed328c980 __restore_rt (/lib/x86_64-linux-gnu/libpthread.so.0+0x12980)
 #5 0x00007f7ed217ce87 raise /build/glibc-uZu3wS/glibc-2.27/signal/../sysdeps/unix/sysv/linux/raise.c:51:0
 #6 0x00007f7ed217e7f1 abort /build/glibc-uZu3wS/glibc-2.27/stdlib/abort.c:81:0
 #7 0x0000000003a014b4 llvm::report_fatal_error(llvm::Twine const&, bool) /home/henry/aflplusplus-isel/llvm-project/llvm/lib/Support/ErrorHandling.cpp:125:5
 #8 0x0000000002b27da9 llvm::RegScavenger::spill(llvm::Register, llvm::TargetRegisterClass const&, int, llvm::MachineInstrBundleIterator<llvm::MachineInstr, false>, llvm::MachineInstrBundleIterator<llvm::MachineInstr, false>&) /home/henry/aflplusplus-isel/llvm-project/llvm/lib/CodeGen/RegisterScavenging.cpp:0:7
 #9 0x0000000002b28cf8 llvm::RegScavenger::scavengeRegisterBackwards(llvm::TargetRegisterClass const&, llvm::MachineInstrBundleIterator<llvm::MachineInstr, false>, bool, int, bool) /home/henry/aflplusplus-isel/llvm-project/llvm/lib/CodeGen/RegisterScavenging.cpp:617:18
#10 0x0000000002b2a235 scavengeVReg(llvm::MachineRegisterInfo&, llvm::RegScavenger&, llvm::Register, bool) /home/henry/aflplusplus-isel/llvm-project/llvm/lib/CodeGen/RegisterScavenging.cpp:673:22
#11 0x0000000002b2981d scavengeFrameVirtualRegsInBlock(llvm::MachineRegisterInfo&, llvm::RegScavenger&, llvm::MachineBasicBlock&) /home/henry/aflplusplus-isel/llvm-project/llvm/lib/CodeGen/RegisterScavenging.cpp:713:25
#12 0x0000000002b2955f llvm::scavengeFrameVirtualRegs(llvm::MachineFunction&, llvm::RegScavenger&) /home/henry/aflplusplus-isel/llvm-project/llvm/lib/CodeGen/RegisterScavenging.cpp:773:10
#13 0x0000000002a42c65 (anonymous namespace)::PEI::runOnMachineFunction(llvm::MachineFunction&) /home/henry/aflplusplus-isel/llvm-project/llvm/lib/CodeGen/PrologEpilogInserter.cpp:273:27
#14 0x0000000002894c85 llvm::MachineFunctionPass::runOnFunction(llvm::Function&) /home/henry/aflplusplus-isel/llvm-project/llvm/lib/CodeGen/MachineFunctionPass.cpp:91:8
#15 0x0000000002f797d6 llvm::FPPassManager::runOnFunction(llvm::Function&) /home/henry/aflplusplus-isel/llvm-project/llvm/lib/IR/LegacyPassManager.cpp:1430:23
#16 0x0000000002f7e602 llvm::FPPassManager::runOnModule(llvm::Module&) /home/henry/aflplusplus-isel/llvm-project/llvm/lib/IR/LegacyPassManager.cpp:1476:16
#17 0x0000000002f7a0a9 (anonymous namespace)::MPPassManager::runOnModule(llvm::Module&) /home/henry/aflplusplus-isel/llvm-project/llvm/lib/IR/LegacyPassManager.cpp:1545:23
#18 0x0000000002f79c1d llvm::legacy::PassManagerImpl::run(llvm::Module&) /home/henry/aflplusplus-isel/llvm-project/llvm/lib/IR/LegacyPassManager.cpp:535:16
#19 0x0000000002f7e8e1 llvm::legacy::PassManager::run(llvm::Module&) /home/henry/aflplusplus-isel/llvm-project/llvm/lib/IR/LegacyPassManager.cpp:1672:3
#20 0x0000000000d2cdbc compileModule(char**, llvm::LLVMContext&) /home/henry/aflplusplus-isel/llvm-project/llvm/tools/llc/llc.cpp:737:41
#21 0x0000000000d2b162 main /home/henry/aflplusplus-isel/llvm-project/llvm/tools/llc/llc.cpp:418:13
#22 0x00007f7ed215fc87 __libc_start_main /build/glibc-uZu3wS/glibc-2.27/csu/../csu/libc-start.c:344:0
#23 0x0000000000d2a96a _start (./llvm-project/build-debug/bin/llc+0xd2a96a)

Reproduction 2

In the following case, the crashes occur when the index arguments for the two getelementptr are greater than some thresholds.

https://godbolt.org/z/j6fK5K5G9

Code

define void @f() {
BB:
  %A = alloca <32 x double>
  %A1 = alloca i64
  %G4 = getelementptr i64, i64* %A1, i32 255    ; crashes when index >= 255
  %G6 = getelementptr i64, i64* %G4, i8 194     ; crashes when index >= 194
  %L = load i64, i64* %G4
  %I = insertelement <32 x double> zeroinitializer, double 0.5, i64 %L
  store i64 %L, i64* %G6
  store <32 x double> %I, <32 x double>* %A
  ret void
}

Stack Trace

LLVM ERROR: Error while trying to spill X17 from class GPR: Cannot scavenge register without an emergency spill slot!
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.
Stack dump:
0.	Program arguments: ./llvm-project/build-debug/bin/llc -mtriple=riscv64 crash-reports/riscv64/4.2.ll
1.	Running pass 'Function Pass Manager' on module 'crash-reports/riscv64/4.2.ll'.
2.	Running pass 'Prologue/Epilogue Insertion & Frame Finalization' on function '@f'
 #0 0x0000000003adad2a llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) /home/henry/aflplusplus-isel/llvm-project/llvm/lib/Support/Unix/Signals.inc:569:11
 #1 0x0000000003adaedb PrintStackTraceSignalHandler(void*) /home/henry/aflplusplus-isel/llvm-project/llvm/lib/Support/Unix/Signals.inc:636:1
 #2 0x0000000003ad9526 llvm::sys::RunSignalHandlers() /home/henry/aflplusplus-isel/llvm-project/llvm/lib/Support/Signals.cpp:103:5
 #3 0x0000000003adb605 SignalHandler(int) /home/henry/aflplusplus-isel/llvm-project/llvm/lib/Support/Unix/Signals.inc:407:1
 #4 0x00007f321f5d1980 __restore_rt (/lib/x86_64-linux-gnu/libpthread.so.0+0x12980)
 #5 0x00007f321e4c1e87 raise /build/glibc-uZu3wS/glibc-2.27/signal/../sysdeps/unix/sysv/linux/raise.c:51:0
 #6 0x00007f321e4c37f1 abort /build/glibc-uZu3wS/glibc-2.27/stdlib/abort.c:81:0
 #7 0x0000000003a014b4 llvm::report_fatal_error(llvm::Twine const&, bool) /home/henry/aflplusplus-isel/llvm-project/llvm/lib/Support/ErrorHandling.cpp:125:5
 #8 0x0000000002b27da9 llvm::RegScavenger::spill(llvm::Register, llvm::TargetRegisterClass const&, int, llvm::MachineInstrBundleIterator<llvm::MachineInstr, false>, llvm::MachineInstrBundleIterator<llvm::MachineInstr, false>&) /home/henry/aflplusplus-isel/llvm-project/llvm/lib/CodeGen/RegisterScavenging.cpp:0:7
 #9 0x0000000002b28cf8 llvm::RegScavenger::scavengeRegisterBackwards(llvm::TargetRegisterClass const&, llvm::MachineInstrBundleIterator<llvm::MachineInstr, false>, bool, int, bool) /home/henry/aflplusplus-isel/llvm-project/llvm/lib/CodeGen/RegisterScavenging.cpp:617:18
#10 0x0000000002b2a235 scavengeVReg(llvm::MachineRegisterInfo&, llvm::RegScavenger&, llvm::Register, bool) /home/henry/aflplusplus-isel/llvm-project/llvm/lib/CodeGen/RegisterScavenging.cpp:673:22
#11 0x0000000002b2981d scavengeFrameVirtualRegsInBlock(llvm::MachineRegisterInfo&, llvm::RegScavenger&, llvm::MachineBasicBlock&) /home/henry/aflplusplus-isel/llvm-project/llvm/lib/CodeGen/RegisterScavenging.cpp:713:25
#12 0x0000000002b2955f llvm::scavengeFrameVirtualRegs(llvm::MachineFunction&, llvm::RegScavenger&) /home/henry/aflplusplus-isel/llvm-project/llvm/lib/CodeGen/RegisterScavenging.cpp:773:10
#13 0x0000000002a42c65 (anonymous namespace)::PEI::runOnMachineFunction(llvm::MachineFunction&) /home/henry/aflplusplus-isel/llvm-project/llvm/lib/CodeGen/PrologEpilogInserter.cpp:273:27
#14 0x0000000002894c85 llvm::MachineFunctionPass::runOnFunction(llvm::Function&) /home/henry/aflplusplus-isel/llvm-project/llvm/lib/CodeGen/MachineFunctionPass.cpp:91:8
#15 0x0000000002f797d6 llvm::FPPassManager::runOnFunction(llvm::Function&) /home/henry/aflplusplus-isel/llvm-project/llvm/lib/IR/LegacyPassManager.cpp:1430:23
#16 0x0000000002f7e602 llvm::FPPassManager::runOnModule(llvm::Module&) /home/henry/aflplusplus-isel/llvm-project/llvm/lib/IR/LegacyPassManager.cpp:1476:16
#17 0x0000000002f7a0a9 (anonymous namespace)::MPPassManager::runOnModule(llvm::Module&) /home/henry/aflplusplus-isel/llvm-project/llvm/lib/IR/LegacyPassManager.cpp:1545:23
#18 0x0000000002f79c1d llvm::legacy::PassManagerImpl::run(llvm::Module&) /home/henry/aflplusplus-isel/llvm-project/llvm/lib/IR/LegacyPassManager.cpp:535:16
#19 0x0000000002f7e8e1 llvm::legacy::PassManager::run(llvm::Module&) /home/henry/aflplusplus-isel/llvm-project/llvm/lib/IR/LegacyPassManager.cpp:1672:3
#20 0x0000000000d2cdbc compileModule(char**, llvm::LLVMContext&) /home/henry/aflplusplus-isel/llvm-project/llvm/tools/llc/llc.cpp:737:41
#21 0x0000000000d2b162 main /home/henry/aflplusplus-isel/llvm-project/llvm/tools/llc/llc.cpp:418:13
#22 0x00007f321e4a4c87 __libc_start_main /build/glibc-uZu3wS/glibc-2.27/csu/../csu/libc-start.c:344:0
#23 0x0000000000d2a96a _start (./llvm-project/build-debug/bin/llc+0xd2a96a)
@llvmbot
Copy link
Member

llvmbot commented Sep 27, 2022

@llvm/issue-subscribers-backend-risc-v

@topperc
Copy link
Collaborator

topperc commented Sep 28, 2022

Reproduction 1 isn't really valid code. This GEP %G = getelementptr <16 x i8>, <16 x i8>* %A, i32 127 is asking for memory starting at A+(127*16). But only 16 bytes of stack space where allocated for A. And only 16+2 bytes where allocated for the function. We create an emergency spill count for scavenging based on the size of the stack that is allocated. This is accessing past what is allocated.

@topperc
Copy link
Collaborator

topperc commented Sep 28, 2022

Reproducer 2 is also accessing past what is allocated.

@DataCorrupted
Copy link
Member

Reproduction 1 isn't really valid code. This GEP %G = getelementptr <16 x i8>, <16 x i8>* %A, i32 127 is asking for memory starting at A+(127*16). But only 16 bytes of stack space where allocated for A. And only 16+2 bytes where allocated for the function. We create an emergency spill count for scavenging based on the size of the stack that is allocated. This is accessing past what is allocated.

I agree that this code is invalid at memory level. However, it follows LLVM Language reference and is syntactically and semantically correct. Therefore, I would hope the backend have some proof to these ill-formed code instead of crashing.

For example, in Reproduction 1, if we change index from 127 to 125, it is still invalid, but the compiler is handling it by ignoring invalid instructions. Our finding is that index 127 , this specific index, crashes the whole compiler.

@topperc
Copy link
Collaborator

topperc commented Sep 28, 2022

I'm not sure I would say we crashed. We issued a fatal error because we didn't know how to proceed. It happens that fatal errors generate a stack trace by default.

For index 125 we didn't need a scratch register to generate the immediates. We didn't ignore anything. We generated these accesses to out of bounds memory.

        sb      a2, 2031(sp)                                                     
        sb      a0, 2030(sp)                                                     
        sb      s0, 2029(sp)                                                     
        sb      t6, 2028(sp)                                                     
        sb      t5, 2027(sp)                                                     
        sb      t4, 2026(sp)                                                     
        sb      t3, 2025(sp)                                                     
        sb      a3, 2024(sp)                                                     
        sb      a4, 2023(sp)                                                     
        sb      a1, 2022(sp)                                                     
        sb      t2, 2021(sp)                                                     
        sb      t1, 2020(sp)                                                     
        sb      t0, 2019(sp)                                                     
        sb      a7, 2018(sp)                                                     
        sb      a6, 2017(sp)                                                     
        sb      a5, 2016(sp)

An index of 128 happens to get lucky and disabled a different optimization so we ended up putting part of the address in a7 and used small offset from it.

        sb      a2, 15(a7)                                                       
        sb      a0, 14(a7)                                                       
        sb      s2, 13(a7)                                                       
        sb      s1, 12(a7)                                                       
        sb      s0, 11(a7)                                                       
        sb      t6, 10(a7)                                                       
        sb      t5, 9(a7)                                                        
        sb      a3, 8(a7)                                                        
        sb      a4, 7(a7)                                                        
        sb      a1, 6(a7)                                                        
        sb      t4, 5(a7)                                                        
        sb      t3, 4(a7)                                                        
        sb      t2, 3(a7)                                                        
        sb      t1, 2(a7)                                                        
        sb      t0, 1(a7)

Exactly what indexes breaks is probably dependent on what other things end up on the stack from other allocations or from spills in register allocation.

@luxufan
Copy link
Contributor

luxufan commented Sep 29, 2022

How about adding an emergency spill slot based on the stack size plus the memory instructions' offset?

@topperc
Copy link
Collaborator

topperc commented Sep 29, 2022

How about adding an emergency spill slot based on the stack size plus the memory instructions' offset?

It's not clear we should increase compile time to scan all of the memory instructions to handle code that isn't valid.

@topperc
Copy link
Collaborator

topperc commented Sep 29, 2022

We think that https://reviews.llvm.org/D98101 will fix this issue and we're going to push forward on that.

@DataCorrupted
Copy link
Member

It seems that this has been fixed. Should we close it?

@topperc topperc closed this as completed Mar 14, 2023
@topperc
Copy link
Collaborator

topperc commented Mar 14, 2023

I think the last commit of D98101 was 4554663

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants