llvm-project
e640d9e7 - [RISCV][GlobalISel] Fix legalizing ‘llvm.va_copy’ intrinsic (#86863)

Commit
1 year ago
[RISCV][GlobalISel] Fix legalizing ‘llvm.va_copy’ intrinsic (#86863) Hi, I spotted a problem when running benchmarking programs on a RISCV64 device. ## Issue Segmentation faults only occurred while running the programs compiled with `GlobalISel` enabled. Here is a small but complete example (it is adopted from [Google's benchmark framework](https://github.com/llvm/llvm-test-suite/blob/95a9f0d0b45056274f0bb4b0e0dd019023e414dc/MicroBenchmarks/libs/benchmark/src/colorprint.cc#L85-L119) to reproduce the issue, ```cpp #include <cstdarg> #include <cstdio> #include <iostream> #include <memory> #include <string> std::string FormatString(const char* msg, va_list args) { // we might need a second shot at this, so pre-emptivly make a copy va_list args_cp; va_copy(args_cp, args); std::size_t size = 256; char local_buff[256]; auto ret = vsnprintf(local_buff, size, msg, args_cp); va_end(args_cp); // currently there is no error handling for failure, so this is hack. // BM_CHECK(ret >= 0); if (ret == 0) // handle empty expansion return {}; else if (static_cast<size_t>(ret) < size) return local_buff; else { // we did not provide a long enough buffer on our first attempt. size = static_cast<size_t>(ret) + 1; // + 1 for the null byte std::unique_ptr<char[]> buff(new char[size]); ret = vsnprintf(buff.get(), size, msg, args); // BM_CHECK(ret > 0 && (static_cast<size_t>(ret)) < size); return buff.get(); } } std::string FormatString(const char* msg, ...) { va_list args; va_start(args, msg); auto tmp = FormatString(msg, args); va_end(args); return tmp; } int main() { std::string Str = FormatString("%-*s %13s %15s %12s", static_cast<int>(20), "Benchmark", "Time", "CPU", "Iterations"); std::cout << Str << std::endl; } ``` Use `clang++ -fglobal-isel -o main main.cpp` to compile it. ## Cause I have examined MIR, it shows that these segmentation faults resulted from a small mistake about legalizing the intrinsic function `llvm.va_copy`. https://github.com/llvm/llvm-project/blob/36e74cfdbde208e384c72bcb52ea638303fb7d67/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp#L451-L453 `DstLst` and `Tmp` are placed in the wrong order. ## Changes I have tweaked the test case `CodeGen/RISCV/GlobalISel/vararg.ll` so that `s0` is used as the frame pointer (not in all checks) which points to the starting address of the save area. I believe that it helps reason about how `llvm.va_copy` is handled.
Author
Parents
Loading