digitalmars.D.ldc - RISC-V port
- =?UTF-8?B?THXDrXM=?= Marques (12/12) May 17 2018 I have druntime working with the RISC-V backend (32-bit / Newlib
- =?UTF-8?B?THXDrXM=?= Marques (5/17) May 17 2018 To clarify: the LLVM IR generated by LDC has the whole code, but
- Johan Engelen (8/12) May 17 2018 Are you using LLVM trunk? RISC-V appears to be under active
- =?UTF-8?B?THXDrXM=?= Marques (13/17) May 17 2018 Yes and no. I used to use the lowRISC patches, since the trunk
- Joakim (5/22) May 19 2018 I doubt any of us had to do much with exception-handling in a
- David Nadlinger (19/22) May 20 2018 I'm not sure there is a single answer to this question, as it is rather
- =?UTF-8?B?THXDrXM=?= Marques (4/17) May 21 2018 Yeah, the GCC port of RISC-V includes exception support.
- =?UTF-8?B?THXDrXM=?= Marques (12/19) May 22 2018 After setting the ExceptionType the exceptions weren't working
- =?UTF-8?B?THXDrXM=?= Marques (3/14) May 22 2018 I still haven't found it. Since this part is LDC specific and not
- =?UTF-8?B?THXDrXM=?= Marques (5/7) May 22 2018 I think I mixed GCC code with clang++ code and came to the wrong
- =?UTF-8?B?THXDrXM=?= Marques (7/11) May 22 2018 Yup, I got the C++ exceptions to more or less work (it now jumps
- =?UTF-8?B?THXDrXM=?= Marques (6/12) May 23 2018 The crashes were because the target didn't implement
- David Nadlinger (7/9) May 23 2018 For future reference: In situations like that, it might be useful to
- =?UTF-8?B?THXDrXM=?= Marques (6/13) May 23 2018 Thanks!
- =?UTF-8?B?THXDrXM=?= Marques (52/58) May 24 2018 Consider this code:
- =?UTF-8?B?THXDrXM=?= Marques (7/18) May 24 2018 Clue: when I call __cxa_throw in D code instead of throwing
- =?UTF-8?B?THXDrXM=?= Marques (43/49) May 24 2018 There is this fragment of code in libgcc's _Unwind_RaiseException
- =?UTF-8?B?THXDrXM=?= Marques (3/5) May 24 2018 Turns out it really was a GCC bug!
I have druntime working with the RISC-V backend (32-bit / Newlib based; I got backend errors for 64-bit; I can't test glibc in 32-bit because AFAIK there's no 32-bit RISC-V Linux). It needed some workarounds due to the lack of proper atomics and TLS support in the backend, as well as Newlib limitations, but that's mostly taken care of. For Phobos to work properly the backend needs to support exceptions. Currently the backend seems to only emit code for the non-exceptional code path. Does anyone here understand what an LLVM backend needs to do to get code generated for the exception stuff (e.g. landingpad, etc.)? I tried to look in the ARM backend but it wasn't very illuminating...
May 17 2018
On Thursday, 17 May 2018 at 15:36:05 UTC, Luís Marques wrote:I have druntime working with the RISC-V backend (32-bit / Newlib based; I got backend errors for 64-bit; I can't test glibc in 32-bit because AFAIK there's no 32-bit RISC-V Linux). It needed some workarounds due to the lack of proper atomics and TLS support in the backend, as well as Newlib limitations, but that's mostly taken care of. For Phobos to work properly the backend needs to support exceptions. Currently the backend seems to only emit code for the non-exceptional code path. Does anyone here understand what an LLVM backend needs to do to get code generated for the exception stuff (e.g. landingpad, etc.)? I tried to look in the ARM backend but it wasn't very illuminating...To clarify: the LLVM IR generated by LDC has the whole code, but the backend behaves as if an exception could never be thrown, and the exception handling stuff gets optimized away. Or so it seems, anyway.
May 17 2018
On Thursday, 17 May 2018 at 15:36:05 UTC, Luís Marques wrote:Does anyone here understand what an LLVM backend needs to do to get code generated for the exception stuff (e.g. landingpad, etc.)? I tried to look in the ARM backend but it wasn't very illuminating...Are you using LLVM trunk? RISC-V appears to be under active development: http://www.lowrisc.org/blog/2017/09/moving-risc-v-llvm-forwards/ http://www.lowrisc.org/llvm/status/ More experts to answer your question are to be found on the llvm-dev mailinglist. -Johan
May 17 2018
On Thursday, 17 May 2018 at 17:45:24 UTC, Johan Engelen wrote:Are you using LLVM trunk? RISC-V appears to be under active development: http://www.lowrisc.org/blog/2017/09/moving-risc-v-llvm-forwards/ http://www.lowrisc.org/llvm/status/Yes and no. I used to use the lowRISC patches, since the trunk version used to be severely behind. But there were some bugs in the patched backend that were preventing further progress. With the latest merges the trunk now seems more usable (more complete, and the bugs exhibited by the patches seem to no longer be there) so I'm using that. In any case, the author is the same (Alex Bradbury). I've been in contact with him, but he goes several months without replying, due to competing priorities and lack of funding. I guess I could ask for help in the llvm-dev mailing list. I thought people here might be more motivated to help, given the focus on D support.
May 17 2018
On Thursday, 17 May 2018 at 18:05:37 UTC, Luís Marques wrote:On Thursday, 17 May 2018 at 17:45:24 UTC, Johan Engelen wrote:I doubt any of us had to do much with exception-handling in a backend, it's just one of those features we get from llvm for free. Since we don't develop backends, you're better off asking the llvm guys, who do.Are you using LLVM trunk? RISC-V appears to be under active development: http://www.lowrisc.org/blog/2017/09/moving-risc-v-llvm-forwards/ http://www.lowrisc.org/llvm/status/Yes and no. I used to use the lowRISC patches, since the trunk version used to be severely behind. But there were some bugs in the patched backend that were preventing further progress. With the latest merges the trunk now seems more usable (more complete, and the bugs exhibited by the patches seem to no longer be there) so I'm using that. In any case, the author is the same (Alex Bradbury). I've been in contact with him, but he goes several months without replying, due to competing priorities and lack of funding. I guess I could ask for help in the llvm-dev mailing list. I thought people here might be more motivated to help, given the focus on D support.
May 19 2018
Hi Luís, On 17 May 2018, at 16:36, Luís Marques via digitalmars-d-ldc wrote:Does anyone here understand what an LLVM backend needs to do to get code generated for the exception stuff (e.g. landingpad, etc.)? I tried to look in the ARM backend but it wasn't very illuminating...I'm not sure there is a single answer to this question, as it is rather broad in scope. First of all, what is the exception ABI for your target? Is it table-based using DWARF frame information? Or is it {set,long}jmp-based? I don't quite remember whether this question has even been addressed for RISC-V so far, that is, whether there even is a compiler port that supports C++ exceptions, or an ABI document that prescribes a particular implementation. If there is none and you want to play around with an initial implementation of *something*, I'd probably choose the vanilla DWARF-based implementation as supported by libunwind. From there, it's a matter of setting the ExceptionType correctly in your MCAsmInfo subclass, and fixing up various other bits and pieces as required. (For example, the code generator might need some tweaks to make sure the frame offset information is up to date, etc.) Grepping lib/Backend for `DwarfCFI` should provide you with some inspiration. Best, David
May 20 2018
On Sunday, 20 May 2018 at 17:32:53 UTC, David Nadlinger wrote:First of all, what is the exception ABI for your target? Is it table-based using DWARF frame information? Or is it {set,long}jmp-based?It's table-based DWARF.I don't quite remember whether this question has even been addressed for RISC-V so far, that is, whether there even is a compiler port that supports C++ exceptions, or an ABI document that prescribes a particular implementation.Yeah, the GCC port of RISC-V includes exception support.From there, it's a matter of setting the ExceptionType correctly in your MCAsmInfo subclass, and fixing up various other bits and pieces as required. (For example, the code generator might need some tweaks to make sure the frame offset information is up to date, etc.) Grepping lib/Backend for `DwarfCFI` should provide you with some inspiration.Cool, I'll look into that.
May 21 2018
On Monday, 21 May 2018 at 13:48:36 UTC, Luís Marques wrote:After setting the ExceptionType the exceptions weren't working correctly even with clang++. After diving into the details I found out that the use of .uleb128 in .gcc_except_table was preventing relocations of symbols referenced in that table from being generated. I changed LLVM's backend configuration in MCObjectFileInfo.cpp to use the correct types and with clang++ exceptions now seem to be working, at least the minimal case I tested. LDC even after rebuilding is still using .uleb128 in .gcc_except_table, which is surprising, since it would seem that that configuration only depends on the chosen triple. So now I'm solving that part of the puzzle.From there, it's a matter of setting the ExceptionType correctly in your MCAsmInfo subclass, and fixing up various other bits and pieces as required. (For example, the code generator might need some tweaks to make sure the frame offset information is up to date, etc.) Grepping lib/Backend for `DwarfCFI` should provide you with some inspiration.Cool, I'll look into that.
May 22 2018
On Tuesday, 22 May 2018 at 12:42:47 UTC, Luís Marques wrote:After setting the ExceptionType the exceptions weren't working correctly even with clang++. After diving into the details I found out that the use of .uleb128 in .gcc_except_table was preventing relocations of symbols referenced in that table from being generated. I changed LLVM's backend configuration in MCObjectFileInfo.cpp to use the correct types and with clang++ exceptions now seem to be working, at least the minimal case I tested. LDC even after rebuilding is still using .uleb128 in .gcc_except_table, which is surprising, since it would seem that that configuration only depends on the chosen triple. So now I'm solving that part of the puzzle.I still haven't found it. Since this part is LDC specific and not LLVM specific, help here would be most appreciated :D
May 22 2018
On Tuesday, 22 May 2018 at 14:31:17 UTC, Luís Marques wrote:I still haven't found it. Since this part is LDC specific and not LLVM specific, help here would be most appreciated :DI think I mixed GCC code with clang++ code and came to the wrong conclusions. But I found in LLVM where I actually have to change to emit the table with .4byte instead of .uleb128.
May 22 2018
On Tuesday, 22 May 2018 at 15:40:14 UTC, Luís Marques wrote:I think I mixed GCC code with clang++ code and came to the wrong conclusions. But I found in LLVM where I actually have to change to emit the table with .4byte instead of .uleb128.Yup, I got the C++ exceptions to more or less work (it now jumps to the catch block, although it currently crashes in __cxa_end_catch with a misaligned instruction access). But that only works if I generate textual assembly and assemble that. If I generate an object file directly no relocations are generated for the table, and so it doesn't work.
May 22 2018
On Tuesday, 22 May 2018 at 18:29:44 UTC, Luís Marques wrote:Yup, I got the C++ exceptions to more or less work (it now jumps to the catch block, although it currently crashes in __cxa_end_catch with a misaligned instruction access). But that only works if I generate textual assembly and assemble that. If I generate an object file directly no relocations are generated for the table, and so it doesn't work.The crashes were because the target didn't implement `getExceptionPointerRegister` and `getExceptionSelectorRegister`. In LLVM and druntime I have assumed those are x10 and x11, AKA a0 and a1, the argument passing/return value registers. Now I have to implement the CFI directives for stack adjustment.
May 23 2018
On 22 May 2018, at 15:31, Luís Marques via digitalmars-d-ldc wrote:I still haven't found it. Since this part is LDC specific and not LLVM specific, help here would be most appreciated :DFor future reference: In situations like that, it might be useful to compile both C++ and D sources to LLVM IR (`-emit-llvm -S` for Clang), and then manually assemble them using `llc`. Any difference in behaviour that remains must then be visible from the IR, rather than some potentially different codegen settings, etc. — David
May 23 2018
On Wednesday, 23 May 2018 at 15:35:12 UTC, David Nadlinger wrote:For future reference: In situations like that, it might be useful to compile both C++ and D sources to LLVM IR (`-emit-llvm -S` for Clang), and then manually assemble them using `llc`. Any difference in behaviour that remains must then be visible from the IR, rather than some potentially different codegen settings, etc.Thanks! You know what's silly? I had activated the debug flag `debug = EH_personality`, but that debug code uses printf with varargs, and I hand't yet ported varargs, so that's what was crashing on the D side... arrg!
May 23 2018
On Wednesday, 23 May 2018 at 16:10:47 UTC, Luís Marques wrote:On Wednesday, 23 May 2018 at 15:35:12 UTC, David Nadlinger wrote: You know what's silly? I had activated the debug flag `debug = EH_personality`, but that debug code uses printf with varargs, and I hand't yet ported varargs, so that's what was crashing on the D side... arrg!Consider this code: extern(C) void drun() { try { throw new Exception("throw test"); } catch(Exception e) { writeln_("caught from D"); } } When an expection is thrown the function _d_throw_exception is called. In turn, it calls _Unwind_RaiseException. But that function fails, returning a high numeric value that isn't part of the expected return type enum (_Unwind_Reason_Code) values. So the D exception personality is never called, and the catch block is never executed. The only thing that is currently missing in the assembly is the CFI stack adjustment directives. But I don't think that's what's causing the problem, because 1) when those are missing in the C++ code basic exception handling still works, and 2) I've tried to manually add those to the assembly file and it makes no difference. I've also tried to make drun only throw a pre-existing __gshared global Exception instance object, to simplify the function and stack adjustment, but it makes no difference. The problem seems to be elsewhere. Here's the assembly for the following code: https://gist.github.com/luismarques/238f5bd98f8dfbf9c6356071dfc9c2c5 pragma(LDC_no_moduleinfo); extern(C) void writeln_(const(char)[] s) nothrow nogc; __gshared Exception e; extern(C) void allocException() { e = new Exception("test exception"); } extern(C) void drun() { try { throw e; } catch(Exception e) { writeln_("caught from D"); } } Any idea on what might be wrong?
May 24 2018
On Thursday, 24 May 2018 at 14:01:48 UTC, Luís Marques wrote:When an expection is thrown the function _d_throw_exception is called. In turn, it calls _Unwind_RaiseException. But that function fails, returning a high numeric value that isn't part of the expected return type enum (_Unwind_Reason_Code) values. So the D exception personality is never called, and the catch block is never executed. The only thing that is currently missing in the assembly is the CFI stack adjustment directives. But I don't think that's what's causing the problem, because 1) when those are missing in the C++ code basic exception handling still works, and 2) I've tried to manually add those to the assembly file and it makes no difference.Clue: when I call __cxa_throw in D code instead of throwing normally (i.e., calling _d_throw_exception), the D personality handler *is* called. Which indicates that, indeed, the problem is *not* in the generated assembly file. So I guess it's something that _d_throw_exception does which isn't quite right, although I can't see what.
May 24 2018
On Thursday, 24 May 2018 at 14:45:26 UTC, Luís Marques wrote:Clue: when I call __cxa_throw in D code instead of throwing normally (i.e., calling _d_throw_exception), the D personality handler *is* called. Which indicates that, indeed, the problem is *not* in the generated assembly file. So I guess it's something that _d_throw_exception does which isn't quite right, although I can't see what.There is this fragment of code in libgcc's _Unwind_RaiseException (printfs inserted by me): code = uw_frame_state_for (&cur_context, &fs); printf("_Unwind_RaiseException uw_frame_state_for %d\n", code); if (code == _URC_END_OF_STACK) { /* Hit end of stack with no handler found. */ printf("_Unwind_RaiseException code == _URC_END_OF_STACK\n"); return _URC_END_OF_STACK; } The code prints: _Unwind_RaiseException uw_frame_state_for 5 _Unwind_RaiseException code == _URC_END_OF_STACK But then the function actually returns a nonsense number instead of the expected 5/_URC_END_OF_STACK. Looking at the disassembly of _Unwind_RaiseException what seems to happen is that the function starts with: 00001db0 <_Unwind_RaiseException>: 1db0: a7010113 addi sp,sp,-1424 1db4: 58912223 sw s1,1412(sp) 1db8: 58a12023 sw a0,1408(sp) // store a0 And then before it returns it does this: 2034: 58012503 lw a0,1408(sp) // load original a0 2038: 59010113 addi sp,sp,1424 203c: 00e10133 add sp,sp,a4 2040: 00008067 ret No other part of that function stores to 1408(sp), so of course a0 (the main return register) returns garbage instead of the more meaningful 5/_URC_END_OF_STACK. GCC is supposed to be reliable, so I would lean towards believing this isn't a miscompilation. The function prototype is: _Unwind_Reason_Code LIBGCC2_UNWIND_ATTRIBUTE _Unwind_RaiseException(struct _Unwind_Exception *exc) So I though maybe LIBGCC2_UNWIND_ATTRIBUTE was modifying the ABI somehow, and the return value wouldn't be in a0 as usual. But grepping my RISC-V GCC source code for that didn't find anything meaningful (only mips seems to define it). And looking at the complete disassembly it doesn't explain how the return value would be returned anyway. So maybe that's a miscompilation? I'll ask in the RISC-V forums.
May 24 2018
On Thursday, 24 May 2018 at 18:31:01 UTC, Luís Marques wrote:GCC is supposed to be reliable, so I would lean towards believing this isn't a miscompilation.Turns out it really was a GCC bug! https://groups.google.com/a/groups.riscv.org/d/msg/sw-dev/_F9m7rDH8YM/UuNUJyC_CgAJ
May 24 2018