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

Rebase ontop of Rust with LLVM 6.0 #90

Closed
dylanmckay opened this issue Feb 19, 2018 · 11 comments
Closed

Rebase ontop of Rust with LLVM 6.0 #90

dylanmckay opened this issue Feb 19, 2018 · 11 comments

Comments

@dylanmckay
Copy link
Member

Rust has recently landed LLVM 6.0 support.

On top of this, it has landed support for multiple LLVM toolchains.

The AVR backend as of LLVM 6.0 has all of the patches included in the avr-rust/llvm fork (but we should double check this). This means that we should have no extra cherry-picked commits for avr-rust, so we will be using the exact same LLVM fork as upstream Rust. We would still very likely need to cherry-pick patches in the future however (but if we can do upstream Rust LLVM upgrades with pace, that is preferable).

With this upgrade, we also have an option:

  • Add a separate LLVM toolchain in a similar fashion to the emscripten toolchain. This would allow us to use whatever LLVM fork we want for the AVR target separate from the LLVM submodule used to compile the standard upstream Rust target
@dylanmckay
Copy link
Member Author

Good news!

I have rebuilt a libcore library based on current Rust master. There are only two bugs blocking full compilation of libcore without modifications.

These are

The rest of libcore works fine.

You can see my branch at dylanmckay/[email protected]

This upgrade should be just about ready

@brainlag
Copy link

So #26 and #37 are not a problem anymore for rust core?

@dylanmckay
Copy link
Member Author

dylanmckay commented Feb 22, 2018

It seems that way so far, in the static core library I've compiled, there's ~1500 symbols defined. All of the functions have machine code.

This includes all of the cmp modules, the non-float fmt module, all of the integer conversion traits and std::ops trait implementations, as well as the core::mem functions, time::Duration stuff and panic routines, and some more.

So I think it's pretty fair to say that, unless there's some other way we could trigger codegen bugs with libcore by having it execute different machine code than I just did in a standard static library build of core (monomorphization?), then #26 must no longer be issues in LLVM 6.0.

I suspect that #37 is still an issue however. The underlying limitation in the register allocation probably still stands. It's possible that LLVM or Rust got smarter at optimizing, causing less register pressure and making the bug harder to trigger.

I have attached the full objdump output for static library core on my machine.

core.a.dump.txt

@brainlag
Copy link

I could only reproduce #26 and #37 with optimization enabled. Are you sure you didn't build core with optimizations disabled?

@dylanmckay
Copy link
Member Author

dylanmckay commented Feb 22, 2018

Interestingly, when I compile the blink example with the 6.0 libcore, I do get this error

LLVM ERROR: ran out of registers during register allocation
error: Could not compile `core`.

@brainlag

I could only reproduce #26 and #37 with optimization enabled. Are you sure you didn't build core with optimizations disabled?

I double checked and yes, you're right - I was compiling with optimisations disabled. When I enable them and build static libcore, I get the same register allocation error (#37).

Seems like we'll have to fix it before we upgrade. I suspect not

@dylanmckay
Copy link
Member Author

It looks like I was compiling libcore with optimisations disabled. When I enable optimisations, I get the "ran out of registers during register allocation" error.

Interestingly, a lot of these errors come from fmt::Debug implementations. Even trivial ones.

@shepmaster
Copy link
Member

Interestingly, a lot of these errors come from fmt::Debug implementations. Even trivial ones.

My underlying suspicion is that the format struct is simply huge and tries to be passed in registers in release mode. In debug mode, it's behind some pointer indirection. I haven't verified this at all.

@dylanmckay
Copy link
Member Author

dylanmckay commented Mar 5, 2018

# Machine code for function _ZN65_$LT$lib..sync..atomic..AtomicBool$u20$as$u20$lib..fmt..Debug$GT$3fmt17hd605133ba71344ebE: NoPHIs, TracksLiveness
Frame Objects:
  fi#0: size=1, align=1, at location [SP+2]
  fi#1: size=6, align=1, at location [SP+2]
Function Live Ins: $r25r24 in %11, $r23r22 in %12

bb.0.start:
  successors: %bb.2(0x40000000), %bb.1(0x40000000); %bb.2(200.00%), %bb.1(200.00%)
  liveins: $r25r24, $r23r22
  %95:ptrdispregs = COPY $r23r22
  %92:dregs = COPY $r25r24
  early-clobber %13:dregs = LDDWRdPtrQ %95:ptrdispregs, 15; mem:LD2[%1](align=1)(noalias=!82,!84,!86,!87,!89)(dereferenceable)
  %96:dregs = COPY %95:ptrdispregs
  %97:ptrdispregs = COPY %96:dregs
  early-clobber %18:ptrdispregs = LDDWRdPtrQ %97:ptrdispregs, 17; mem:LD2[%4](align=1)(noalias=!82,!84,!86,!87,!89)(dereferenceable)
  early-clobber %17:dregs = LDDWRdPtrQ %18:ptrdispregs, 6; mem:LD2[%6](align=1)(noalias=!82,!84,!86,!87,!89)(invariant)
  ADJCALLSTACKDOWN 0, 0, implicit-def dead $sp, implicit-def dead $sreg, implicit $sp
  %19:dldregs = LDIWRdK @str.w
  %20:dldregs = LDIWRdK 10
  $r25r24 = COPY %13:dregs
  $r23r22 = COPY %19:dldregs
  $r21r20 = COPY %20:dldregs
  $r31r30 = COPY %17:dregs

  ICALL $r31r30, $r25r24, $r23r22, $r21r20, <regmask $r2 $r3 $r4 $r5 $r6 $r7 $r8 $r9 $r10 $r11 $r12 $r13 $r14 $r15 $r16 $r17 $r28 $r29 $r3r2 $r5r4 $r7r6 $r9r8 $r11r10 $r13r12 $r15r1
4 $r17r16 $r29r28>, implicit $sp, implicit $r31r30, implicit-def $sp, implicit-def $r24

  ADJCALLSTACKUP 0, 0, implicit-def dead $sp, implicit-def dead $sreg, implicit $sp
  %21:gpr8 = COPY $r24
  STDWPtrQRr %stack.1._6, 0, %96:dregs; mem:ST2[%9](align=1)(alias.scope=!84,!87)(noalias=!86,!89)
  STDPtrQRr %stack.1._6, 2, %21:gpr8; mem:ST1[%10](alias.scope=!84,!87)(noalias=!86,!89)
  %22:dldregs = LDIWRdK 0
  STDWPtrQRr %stack.1._6, 3, %22:dldregs; mem:ST2[%12](align=1)(alias.scope=!84,!87)(noalias=!86,!89)
  %23:ld8 = LDIRdK 0
  STDPtrQRr %stack.1._6, 5, %23:ld8; mem:ST1[%13](alias.scope=!84,!87)(noalias=!86,!89)
  %93:ptrregs = COPY %92:dregs
  %24:ld8 = AtomicLoad8 %93:ptrregs; mem:Volatile LD1[%self]
  %83:ld8 = LDIRdK 1
  CPIRdK %24:ld8, 0, implicit-def $sreg
  BRNEk %bb.1, implicit killed $sreg
  RJMPk %bb.2

look at that ICALL, damn

@shepmaster
Copy link
Member

Perhaps the AVR backend needs different logic for when something needs to use indirection and not use up all the registers?

@dylanmckay
Copy link
Member Author

Have raised #95 for the "ran out of registers" problem

@shepmaster
Copy link
Member

We've recently upgraded to LLVM 8 🎉 I'm going to close any bug that is reported against an older version of LLVM. If you are still having this issue with the LLVM-8 based code, please ping me and I can reopen the issue!

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

No branches or pull requests

3 participants