Git Product home page Git Product logo

avr-rust / rust-legacy-fork Goto Github PK

View Code? Open in Web Editor NEW

This project forked from rust-lang/rust

493.0 493.0 14.0 527.33 MB

[deprecated; merged upstream] A fork of the Rust programming language with AVR support

License: Other

Makefile 0.32% Rust 97.44% CSS 0.16% Python 0.56% Shell 0.23% C 0.07% C++ 0.33% JavaScript 0.45% Puppet 0.01% Lex 0.03% Yacc 0.25% Pascal 0.03% HTML 0.01% PHP 0.01% Inno Setup 0.03% XSLT 0.01% Batchfile 0.01% Assembly 0.03% RenderScript 0.01% Roff 0.04%
arduino avr rust

rust-legacy-fork's Introduction

Rust with AVR support

Gitter

This project adds support for the AVR microcontroller to Rust.

It uses the AVR-LLVM backend.

Caveats

While the stock libcore may be compiled, certain code patterns may still exercise code in LLVM that is broken or that produces miscompiled code. Looking for existing issues or submitting a new issue is appreciated!

Building and installation

This will compile Rust with AVR support. This will not create a fully-fledged cross-compiler, however, as it does not compile any libraries such as libcore or liblibc. To do this, the --target=avr-unknown-unknown flag must be passed to configure, which is not fully supported yet due to bugs.

First make sure you've installed all dependencies for building, as specified in the main Rust repository here. Then use the following commands:

Unix/Linux/*nix

# Grab the avr-rust sources
git clone https://github.com/avr-rust/rust.git --recursive

# Create a directory to place built files in
mkdir build && cd build

# Generate Makefile using settings suitable for an experimental compiler
../rust/configure \
  --enable-debug \
  --disable-docs \
  --enable-llvm-assertions \
  --enable-debug-assertions \
  --enable-optimize \
  --enable-llvm-release-debuginfo \
  --experimental-targets=AVR \
  --prefix=/opt/avr-rust

# Build the compiler, optionally install it to /opt/avr-rust
make
make install

# Register the toolchain with rustup
rustup toolchain link avr-toolchain $(realpath $(find . -name 'stage2'))

# Optionally enable the avr toolchain globally
rustup default avr-toolchain

Notes for macOS

The conventional install directory for macOS is /usr/local/avr-rust rather than the Linux default /opt/avr-rust, so before the steps below, you must:

  1. Edit build/config.toml to set prefix = '/usr/local/avr-rust'.
  2. Ensure /usr/local/avr-rust exists and has the correct permissions: sudo mkdir /usr/local/avr-rust && sudo chown ${USER}:admin /usr/local/avr-rust

Finally, realpath isn't included by default on macOS but is included in GNU Coreutils, so you can either brew install coreutils so the rustup toolchain... step works properly, or just use the explicit path (rustup toolchain link avr-toolchain /usr/local/avr-rust).

# Grab the avr-rust sources
git clone https://github.com/avr-rust/rust.git --recursive

# Create a directory to place built files in
mkdir build && cd build

# Generate Makefile using settings suitable for an experimental compiler
../rust/configure \
  --enable-debug \
  --disable-docs \
  --enable-llvm-assertions \
  --enable-debug-assertions \
  --enable-optimize \
  --enable-llvm-release-debuginfo \
  --experimental-targets=AVR \
  --prefix=/usr/local/avr-rust

# Build the compiler, install it to /usr/local/avr-rust
make
make install

# Register the toolchain with rustup
rustup toolchain link avr-toolchain /usr/local/avr-rust

# Optionally enable the avr toolchain globally
rustup default avr-toolchain

Usage

With Xargo (recommended)

Take a look at the example blink program.

Vanilla rustc

AVR support is enabled by passing the --target avr-unknown-unknown flag to rustc.

Note that the Rust libcore library (essentially required for every Rust program), must be manually compiled for it to be used, as it will not be built for AVR during compiler compilation (yet). Work is currently being done in order to allow libcore to be automatically compiled for AVR.

rust-legacy-fork's People

Contributors

alexcrichton avatar bors avatar brson avatar catamorphism avatar centril avatar eddyb avatar erickt avatar estebank avatar frewsxcv avatar graydon avatar guillaumegomez avatar huonw avatar jseyfried avatar kennytm avatar manishearth avatar marijnh avatar mark-simulacrum avatar michaelwoerister avatar nikomatsakis avatar nrc avatar oli-obk avatar pcwalton avatar petrochenkov avatar pnkfelix avatar ralfjung avatar solson avatar steveklabnik avatar thestinger avatar varkor avatar zoxc avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rust-legacy-fork's Issues

"Relocation truncated to fit" from branches in long functions

As mentioned in #36 (comment), I got around #36 by inlining lots of functions. However, the resulting code cannot be linked because, I quote avr-gcc:

target/avr-atmega328p/release/deps/chip8_avr-41c427b8d446a439.o: In function `LBB5_18':
chip8_avr.cgu-0.rs:(.text.main+0x432): relocation truncated to fit: R_AVR_7_PCREL against `no symbol'
target/avr-atmega328p/release/deps/chip8_avr-41c427b8d446a439.o: In function `LBB5_23':
chip8_avr.cgu-0.rs:(.text.main+0x45c): relocation truncated to fit: R_AVR_7_PCREL against `no symbol'
target/avr-atmega328p/release/deps/chip8_avr-41c427b8d446a439.o: In function `LBB5_31':
chip8_avr.cgu-0.rs:(.text.main+0x4ae): relocation truncated to fit: R_AVR_7_PCREL against `no symbol'
target/avr-atmega328p/release/deps/chip8_avr-41c427b8d446a439.o: In function `LBB5_34':
chip8_avr.cgu-0.rs:(.text.main+0x4d2): relocation truncated to fit: R_AVR_7_PCREL against `no symbol'
target/avr-atmega328p/release/deps/chip8_avr-41c427b8d446a439.o: In function `LBB5_146':
chip8_avr.cgu-0.rs:(.text.main+0x58a): relocation truncated to fit: R_AVR_7_PCREL against `no symbol'
chip8_avr.cgu-0.rs:(.text.main+0x58e): relocation truncated to fit: R_AVR_7_PCREL against `no symbol'
chip8_avr.cgu-0.rs:(.text.main+0x592): relocation truncated to fit: R_AVR_7_PCREL against `no symbol'
target/avr-atmega328p/release/deps/chip8_avr-41c427b8d446a439.o: In function `LBB5_153':
chip8_avr.cgu-0.rs:(.text.main+0x59a): relocation truncated to fit: R_AVR_7_PCREL against `no symbol'
chip8_avr.cgu-0.rs:(.text.main+0x59e): relocation truncated to fit: R_AVR_7_PCREL against `no symbol'
chip8_avr.cgu-0.rs:(.text.main+0x5a6): relocation truncated to fit: R_AVR_7_PCREL against `no symbol'
chip8_avr.cgu-0.rs:(.text.main+0x5aa): additional relocation overflows omitted from the output
collect2: error: ld returned 1 exit status

However, looking at those places, all those branches that the linker tries to rewrite to a long address, they look quite superfluous to me. For example, the first one at 0x432:

     432:       01 f4           brne    .+0             ; 0x434 <LBB5_18+0x8>

Isn't that a conditional branch to exactly the next instruction? A roundabout, two-byte NOP?

I looked at all the locations mentioned in the linker error messages, and they are all of this form (some brne, some brcs, some brge, but all jump to exactly the next instruction).

Merge changes into upstream Rust

This issue is for discussion on upstreaming AVR support to upstream Rust.

Things we need to do first

One thing that I am concerned about is how hard it is going to be in order to add avr-llvm patches in order to fix codegen bugs - if AVR support is in Rust master, we will have to get AVR backend patches into the Rust LLVM fork. This may cause us to have longish periods of time where a single bug stops all users from using AVR.

Upgrade to support LLVM 4.0 (development)

I get this in the tip of avr-support-4.0

configure --enable-debug --disable-docs --enable-llvm-assertions --enable-debug-assertions --enable-rustbuild
make rustc-stage1
Building stage1 std artifacts (x86_64-apple-darwin -> x86_64-apple-darwin)
   Compiling core v0.0.0 (file:///Users/dylanmckay/projects/avr-rust/rust/src/libcore)

Assertion failed: (isa<X>(Val) && "cast<Ty>() argument of incompatible type!"), function cast, file /Users/dylanmckay/projects/builds/avr-rust/rust/build/x86_64-apple-darwin/llvm/include/llvm/Support/Casting.h, line 237.
error: Could not compile `core`.

This triggers it

 build/x86_64-apple-darwin/stage1/bin/rustc /Users/dylanmckay/projects/avr-rust/rust/src/libcore/lib.rs --crate-name core --crate-type lib -C debug-assertions=off -C metadata=877272a66b7a4e4d -C extra-filename=-877272a66b7a4e4d --out-dir ./libcore --target x86_64-apple-darwin -L dependency=/Users/dylanmckay/projects/builds/avr-rust/rust/build/x86_64-apple-darwin/stage1-std/x86_64-apple-darwin/debug/deps --cfg stage1 --sysroot /Users/dylanmckay/projects/builds/avr-rust/rust/build/x86_64-apple-darwin/stage1 -g -C debug-assertions=y -C codegen-units=1 --emit llvm-ir -o libcore.ll

LDDWRdYQ - Bad machine code: Using an undefined physical register

Found while compiling libcore with the patch from #27 applied

libcore.ll

Reproduction

./bin/llc ~/libcore.ll -O0 -o /dev/null
*** Bad machine code: Using an undefined physical register ***
- function:    _ZN76_$LT$core..char..EscapeDefault$u20$as$u20$core..iter..iterator..Iterator$GT$4next17hd387834b920a4d78E
- basic block: BB#3 bb2 (0x7fb1b59aea38)
- instruction: %R29R28<earlyclobber,def> = LDDWRdYQ
- operand 1:   %R29R28

*** Bad machine code: Using an undefined physical register ***
- function:    _ZN76_$LT$core..char..EscapeDefault$u20$as$u20$core..iter..iterator..Iterator$GT$4next17hd387834b920a4d78E
- basic block: BB#3 bb2 (0x7fb1b59aea38)
- instruction: %R31R30<earlyclobber,def> = LDDWRdYQ
- operand 1:   %R29R28

*** Bad machine code: Using an undefined physical register ***
- function:    _ZN76_$LT$core..char..EscapeDefault$u20$as$u20$core..iter..iterator..Iterator$GT$4next17hd387834b920a4d78E
- basic block: BB#3 bb2 (0x7fb1b59aea38)
- instruction: %R21R20<earlyclobber,def> = LDDWRdYQ
- operand 1:   %R29R28
LLVM ERROR: Found 3 machine code errors.

Collection of all bugfixes required to get everything working

This issue is used for listing all bugfixes that we need to get into the LLVM fork before the compiler is usable.

This list will be added to over time.

  • Invalid machine code in .elf file (#39)
  • LDDWRdYQ - Bad machine code: Using an undefined physical register (#32)
  • Assertion failed: (DstReg != SrcReg && "SrcReg and DstReg cannot be the same") (#27)

Potential bug in shl operator implementation

avrio.c.txt
avrio.ll.txt
blink.s.txt

I notice that this IL...

pinMask.exit:                                     ; preds = %entry, %if.then7.i
  %conv.i.sink = phi i16 [ %sub.i, %if.then7.i ], [ %conv.i, %entry ]
  %shl.i = shl i16 1, %conv.i.sink
  %conv3.i = trunc i16 %shl.i to i8
  %tobool = icmp eq i8 %conv3.i, 0
  br i1 %tobool, label %cleanup, label %if.end

There is what looks like an error with the shl operator implementation.

This seems to be the assembly language created...

00000162 <LBB2_3>:
 162:	21 e0       	ldi	r18, 0x01	; 1
 164:	30 e0       	ldi	r19, 0x00	; 0
 166:	e0 15       	cp	r30, r0
 168:	21 f0       	breq	.+8      	; 0x172 <LBB2_5>

0000016a <LBB2_4>:
 16a:	22 0f       	add	r18, r18
 16c:	33 1f       	adc	r19, r19
 16e:	e1 50       	subi	r30, 0x01	; 1
 170:	e1 f7       	brne	.-8      	; 0x16a <LBB2_4>

00000172 <LBB2_5>:

I think the issue is with cp r30, r0. I don't see anywhere in the full assembly that r0 is set, meaning that it could be any value. After a power on it should probably be 0 so this may work in most cases but it looks like a bug. Should it not instead be cpi r30, 00?

It's pretty weird that this IL resulted from compiling the attached c file as I've tried very hard to force unsigned char as the data type everywhere but that's a front end issue rather than an IL -> AVR ASM issue.

Assertion failed: (InVals.size() == Ins.size() && "LowerFormalArguments didn't emit the correct number of values!")

Found while compiling libcore with the patch from #27 and #32 applied

libcore.ll

./bin/llc ~/libcore.ll -O0 -o /dev/null
Assertion failed: (InVals.size() == Ins.size() && "LowerFormalArguments didn't emit the correct number of values!"), function LowerArguments, file /Users/dylan/projects/llvm-project/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp, line 8300.
0  libLLVMSupport.dylib      0x000000010e6da30c llvm::sys::PrintStackTrace(llvm::raw_ostream&) + 60
1  libLLVMSupport.dylib      0x000000010e6da859 PrintStackTraceSignalHandler(void*) + 25
2  libLLVMSupport.dylib      0x000000010e6d6989 llvm::sys::RunSignalHandlers() + 425
3  libLLVMSupport.dylib      0x000000010e6daba2 SignalHandler(int) + 354
4  libsystem_platform.dylib  0x00007fff92361b3a _sigtramp + 26
5  libsystem_platform.dylib  0x0100000100000000 _sigtramp + 1841947872
6  libsystem_c.dylib         0x00007fff921e6420 abort + 129
7  libsystem_c.dylib         0x00007fff921ad893 basename_r + 0
8  libLLVMSelectionDAG.dylib 0x000000010e039290 llvm::SelectionDAGISel::LowerArguments(llvm::Function const&) + 4864
9  libLLVMSelectionDAG.dylib 0x000000010e0f2244 llvm::SelectionDAGISel::SelectAllBasicBlocks(llvm::Function const&) + 612
10 libLLVMSelectionDAG.dylib 0x000000010e0f04de llvm::SelectionDAGISel::runOnMachineFunction(llvm::MachineFunction&) + 2350
11 libLLVMAVRCodeGen.dylib   0x000000010a0a3d0b llvm::AVRDAGToDAGISel::runOnMachineFunction(llvm::MachineFunction&) + 59
12 libLLVMCodeGen.dylib      0x000000010b6db481 llvm::MachineFunctionPass::runOnFunction(llvm::Function&) + 449
13 libLLVMCore.dylib         0x000000010c6eb24f llvm::FPPassManager::runOnFunction(llvm::Function&) + 399
14 libLLVMCore.dylib         0x000000010c6eb755 llvm::FPPassManager::runOnModule(llvm::Module&) + 117
15 libLLVMCore.dylib         0x000000010c6ec524 (anonymous namespace)::MPPassManager::runOnModule(llvm::Module&) + 2196
16 libLLVMCore.dylib         0x000000010c6eba16 llvm::legacy::PassManagerImpl::run(llvm::Module&) + 342
17 libLLVMCore.dylib         0x000000010c6ed251 llvm::legacy::PassManager::run(llvm::Module&) + 33
18 llc                       0x00000001055bec80 compileModule(char**, llvm::LLVMContext&) + 21856
19 llc                       0x00000001055b8b1f main + 2447
20 libdyld.dylib             0x00007fff92152235 start + 1
21 libdyld.dylib             0x0000000000000005 start + 1844108753
Stack dump:
0.      Program arguments: ./bin/llc /Users/dylan/libcore.bc -o /Users/dylan/libcore -O0
1.      Running pass 'Function Pass Manager' on module '/Users/dylan/libcore.bc'.
2.      Running pass 'AVR DAG->DAG Instruction Selection' on function '@"_ZN40_$LT$u128$u20$as$u20$core..num..Zero$GT$4zero17hea846d9fb7aa688eE"'
[1]    5660 abort      ./bin/llc ~/libcore.bc -o ~/libcore -O0

Compile `core` crate for AVR

Rust's standard core crate contains standard platform independent code. Currently we do not build any libraries along with avr-rust, which means that we must:

  • Manually add a Sized trait in all programs
  • Manually add other needed lang-item's

core::intrinsics also contains routines which could be used to provide volatile reads/writes, so that LLVM doesn't optimize away our register loads/stores like it does now.

R_AVR_7_PCREL when linking, seems related to BRNE code emitted?

The attached file simple.swift is compiled to LLVM bytecode simple.ll and assembly simple.o.s.

It fails when run through the linker (avr-gcc/avr-ld) with the above error.

Investigating, the problem seems to be around here (for example)...

  d4:	34 17       	cp	r19, r20
  d6:	41 e0       	ldi	r20, 0x01	; 1
  d8:	01 f4       	brne	.+0      	; 0xda <LBB0_7+0x6>
  da:	40 e0       	ldi	r20, 0x00	; 0
  dc:	00 c0       	rjmp	.+0      	; 0xde <LBB0_10>

When the linker tries to hook up the brne, that's a jump back to the start of the main() routine but in this case the main routine is more than 128 bytes (64 words) long, so BRNE cannot jump that far.

This is starting to show up in larger functions, if bits are removed it links fine.

The problem is how to solve this, the code needs to be smart enough to detect in this case the jump will be too far and turn it into a combination of BRNE and some RJMP instructions.

simple.ll.txt
simple.o.s.txt
simple.swift.txt

Switch lookup tables are not properly placed in program memory

The input code here is a slight tweak of #46, but the generated code is very different because it uses a lookup instead of bit-twiddling:

Rust:

#[inline(never)]
pub fn decode(n: u8) -> Option<()> {
    match n {
        0x0 => Some(()),
        0x1 => Some(()),
        0x2 => Some(()),
        0x3 => Some(()),
        0x4 => Some(()),
        0xe => Some(()),
        _ => None
    }
}

LLVM IR:

        .text
        .file   "external-05dffe7586b7d437.ll"
        .globl  _ZN8external6decode17h0bb113af5b7a3594E
        .p2align        1
        .type   _ZN8external6decode17h0bb113af5b7a3594E,@function
_ZN8external6decode17h0bb113af5b7a3594E: ; @_ZN8external6decode17h0bb113af5b7a3594E
; BB#0:                                 ; %start
        cpi     r24, 15
        brlo    .+2
        rjmp    LBB0_1
; BB#2:                                 ; %switch.lookup
        mov     r26, r24
        mov     r27, r24
        lsl     r27
        sbc     r27, r27
        subi    r26, -lo8(switch.table)
        sbci    r27, -hi8(switch.table)
        ld      r24, X
        ret
LBB0_1:
        ldi     r24, 0
        ret
.Lfunc_end0:
        .size   _ZN8external6decode17h0bb113af5b7a3594E, .Lfunc_end0-_ZN8external6decode17h0bb113af5b7a3594E

        .type   switch.table,@object    ; @switch.table
        .section        .rodata,"a",@progbits
switch.table:
        .ascii  "\001\001\001\001\001\000\000\000\000\000\000\000\000\000\001"
        .size   switch.table, 15

AVR assembly:

Contents of section .text:
 0000 8f3008f0 00c0a82f b82fbb0f bb0ba050  .0....././.....P
 0010 b0408c91 089580e0 0895               .@........      
Contents of section .rodata:
 0000 01010101 01000000 00000000 000001    ............... 

Disassembly of section .text:

00000000 <_ZN8external6decode17h0bb113af5b7a3594E>:
   0:   8f 30           cpi     r24, 0x0F       ; 15
   2:   08 f0           brcs    .+2             ; 0x6 <_ZN8external6decode17h0bb113af5b7a3594E+0x6>
   4:   00 c0           rjmp    .+0             ; 0x6 <_ZN8external6decode17h0bb113af5b7a3594E+0x6>
                        4: R_AVR_13_PCREL       .text+0x16
   6:   a8 2f           mov     r26, r24
   8:   b8 2f           mov     r27, r24
   a:   bb 0f           add     r27, r27
   c:   bb 0b           sbc     r27, r27
   e:   a0 50           subi    r26, 0x00       ; 0
                        e: R_AVR_LO8_LDI_NEG    .rodata
  10:   b0 40           sbci    r27, 0x00       ; 0
                        10: R_AVR_HI8_LDI_NEG   .rodata
  12:   8c 91           ld      r24, X
  14:   08 95           ret

00000016 <LBB0_1>:
  16:   80 e0           ldi     r24, 0x00       ; 0
  18:   08 95           ret

Assertion failed: (MI && "No instruction defining live value"), function computeDeadValues

A reproduction:

; ModuleID = 'bugpoint-reduced-simplified.bc'
source_filename = "bugpoint-output-7b72b44.bc"
target datalayout = "e-p:16:16:16-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-n8"
target triple = "avr"

%BN1.0.5.14.17.18.19.21.26.29.31.34.40.42.57.71.80.84.89.91.95.105 = type { i16, [2 x i8], [40 x i32], [0 x i8] }

@DragonCodeAlpha = external constant [14 x i32], align 4

; Function Attrs: uwtable
define nonnull dereferenceable(164) %BN1.0.5.14.17.18.19.21.26.29.31.34.40.42.57.71.80.84.89.91.95.105* @DragonAlpha(%BN1.0.5.14.17.18.19.21.26.29.31.34.40.42.57.71.80.84.89.91.95.105* returned dereferenceable(164), i16) unnamed_addr #0 personality i32 (...)* @rust_eh_personality {
start:
  %ret.i = alloca [40 x i32], align 4
  br i1 undef, label %bb5, label %bb1

bb1:                                              ; preds = %start
  unreachable

bb5:                                              ; preds = %start
  %2 = icmp eq i16 undef, 0
  br i1 %2, label %bb10, label %bb8

bb8:                                              ; preds = %bb5
  unreachable

bb10:                                             ; preds = %bb5
  %3 = bitcast [40 x i32]* %ret.i to i8*
  %4 = load i16, i16* undef, align 2
  %5 = getelementptr inbounds %BN1.0.5.14.17.18.19.21.26.29.31.34.40.42.57.71.80.84.89.91.95.105, %BN1.0.5.14.17.18.19.21.26.29.31.34.40.42.57.71.80.84.89.91.95.105* %0, i16 0, i32 2, i16 0
  br i1 undef, label %bb2.i38, label %bb3.i39

bb2.i38:                                          ; preds = %bb10
  %6 = getelementptr inbounds %BN1.0.5.14.17.18.19.21.26.29.31.34.40.42.57.71.80.84.89.91.95.105, %BN1.0.5.14.17.18.19.21.26.29.31.34.40.42.57.71.80.84.89.91.95.105* %0, i16 0, i32 2, i16 %4
  br label %bb4.outer.i122

bb4.outer.i122:                                   ; preds = %bb24.i141, %bb2.i38
  %iter.sroa.7.0.ph.i120 = phi i16 [ %8, %bb24.i141 ], [ 0, %bb2.i38 ]
  %retsz.0.ph.i121 = phi i16 [ %.retsz.0.i140, %bb24.i141 ], [ 0, %bb2.i38 ]
  br label %bb4.i125

bb4.i125:                                         ; preds = %EnumerateAlpha, %bb4.outer.i122
  %iter.sroa.7.0.i124 = phi i16 [ %8, %EnumerateAlpha ], [ %iter.sroa.7.0.ph.i120, %bb4.outer.i122 ]
  %7 = icmp eq i32* undef, %6
  br i1 %7, label %_ZN4core3num6bignum8Big32x4010mul_digits17hb016ab455b44b71bE.exit44, label %EnumerateAlpha

EnumerateAlpha:                                   ; preds = %bb4.i125
  %8 = add i16 %iter.sroa.7.0.i124, 1
  %9 = icmp eq i32 undef, 0
  br i1 %9, label %bb4.i125, label %EnumerateBeta

EnumerateBeta:                                    ; preds = %EnumerateAlpha
  %10 = zext i32 undef to i64
  br label %EnumerateGamma

EnumerateGamma:                                   ; preds = %EnumerateBeta
  %11 = icmp ult i16 undef, 40
  br i1 %11, label %SliceMutAlpha, label %panic.i.i14.i134, !prof !0

bb16.i133:                                        ; preds = %SliceMutAlpha
  br i1 undef, label %bb24.i141, label %bb21.i136

panic.i.i14.i134:                                 ; preds = %EnumerateGamma
  unreachable

SliceMutAlpha:                                    ; preds = %EnumerateGamma
  %12 = load i32, i32* undef, align 4, !alias.scope !1, !noalias !4
  %13 = zext i32 %12 to i64
  %14 = mul nuw i64 %13, %10
  %15 = add i64 0, %14
  %16 = lshr i64 %15, 32
  %17 = trunc i64 %15 to i32
  store i32 %17, i32* undef, align 4, !noalias !6
  br label %bb16.i133

bb21.i136:                                        ; preds = %bb16.i133
  br i1 undef, label %SliceMutBeta, label %panic.i.i.i137, !prof !0

panic.i.i.i137:                                   ; preds = %bb21.i136
  unreachable

SliceMutBeta:                                     ; preds = %bb21.i136
  br label %bb24.i141

bb24.i141:                                        ; preds = %SliceMutBeta, %bb16.i133
  %18 = add i16 0, %iter.sroa.7.0.i124
  %19 = icmp ult i16 %retsz.0.ph.i121, %18
  %.retsz.0.i140 = select i1 %19, i16 %18, i16 %retsz.0.ph.i121
  br label %bb4.outer.i122

bb3.i39:                                          ; preds = %bb10
  %20 = call fastcc i16 @BignumInnerAlpha([40 x i32]* nonnull dereferenceable(160) %ret.i, i32* noalias nonnull readonly getelementptr inbounds ([14 x i32], [14 x i32]* @DragonCodeAlpha, i16 0, i16 0), i16 14, i32* noalias nonnull readonly %5, i16 %4)
  br label %_ZN4core3num6bignum8Big32x4010mul_digits17hb016ab455b44b71bE.exit44

_ZN4core3num6bignum8Big32x4010mul_digits17hb016ab455b44b71bE.exit44: ; preds = %bb3.i39, %bb4.i125
  %retsz.0.i40 = phi i16 [ %20, %bb3.i39 ], [ %retsz.0.ph.i121, %bb4.i125 ]
  %21 = getelementptr inbounds %BN1.0.5.14.17.18.19.21.26.29.31.34.40.42.57.71.80.84.89.91.95.105, %BN1.0.5.14.17.18.19.21.26.29.31.34.40.42.57.71.80.84.89.91.95.105* %0, i16 0, i32 2
  %22 = bitcast [40 x i32]* %21 to i8*
  call void @llvm.memcpy.p0i8.p0i8.i16(i8* %22, i8* nonnull %3, i16 160, i32 4, i1 false), !noalias !7
  store i16 %retsz.0.i40, i16* undef, align 2, !noalias !7
  %23 = and i16 %1, 256
  %24 = icmp eq i16 %23, 0
  br i1 %24, label %bb30, label %bb27

bb27:                                             ; preds = %_ZN4core3num6bignum8Big32x4010mul_digits17hb016ab455b44b71bE.exit44
  unreachable

bb30:                                             ; preds = %_ZN4core3num6bignum8Big32x4010mul_digits17hb016ab455b44b71bE.exit44
  ret %BN1.0.5.14.17.18.19.21.26.29.31.34.40.42.57.71.80.84.89.91.95.105* %0
}

; Function Attrs: uwtable
declare fastcc i16 @BignumInnerAlpha([40 x i32]* nocapture dereferenceable(160), i32* noalias nonnull readonly, i16, i32* noalias nonnull readonly, i16) unnamed_addr #0

; Function Attrs: argmemonly nounwind
declare void @llvm.memcpy.p0i8.p0i8.i16(i8* nocapture writeonly, i8* nocapture readonly, i16, i32, i1) #1

declare i32 @rust_eh_personality(...) unnamed_addr

attributes #0 = { uwtable }
attributes #1 = { argmemonly nounwind }

!0 = !{!"branch_weights", i32 2000, i32 1}
!1 = !{!2}
!2 = distinct !{!2, !3, !"BignumInnerAlpha: argument 1"}
!3 = distinct !{!3, !"BignumInnerAlpha"}
!4 = !{!5}
!5 = distinct !{!5, !3, !"BignumInnerAlpha: argument 0"}
!6 = !{!5, !2}
!7 = !{!8}
!8 = distinct !{!8, !9, !"_ZN4core3num6bignum8Big32x4010mul_digits17hb016ab455b44b71bE: argument 0"}
!9 = distinct !{!9, !"_ZN4core3num6bignum8Big32x4010mul_digits17hb016ab455b44b71bE"}

"Cannot select" for str::slice_error_fail

This came up while trying to add str back to libcore-mini:

LLVM IR, minimized as far as I could:

target triple = "avr-atmel-none"

; Function Attrs: cold noinline noreturn nounwind uwtable
define void @_ZN4core3str16slice_error_fail17ha9abe7236f6b8737E(i8* noalias nonnull readonly, i16, i16, i16) {
bb7.i.i23:           
  %vnot..i = icmp ugt i16 %1, %2
  br i1 %vnot..i, label %"is_char_boundary17h47e8e2cd965eb5cbE.exit", label %bb24.preheader

bb24.preheader:  
  %vchar_start.0.ph = phi i16 [ %2, %bb7.i.i23 ], [ %2, %"is_char_boundary17h47e8e2cd965eb5cbE.exit" ], [ %3, %"exit.thread" ]
  %v16 = icmp eq i16 %vchar_start.0.ph, 0
  %v17 = icmp eq i16 %vchar_start.0.ph, %1
  %vor.cond.i1353 = or i1 %v16, %v17
  br i1 %vor.cond.i1353, label %bb33, label %bb33

"is_char_boundary17h47e8e2cd965eb5cbE.exit":
  %v18 = getelementptr inbounds i8, i8* %0, i16 %2
  %v19 = load i8, i8* %v18, align 1
  %v20 = icmp sgt i8 %v19, -65
  br i1 %v20, label %"exit.thread", label %bb24.preheader

"exit.thread": 
  br label %bb24.preheader
  
bb33:
  br label %bb33
}

Error message:

LLVM ERROR: Cannot select: 
t27: ch = RBRCOND t0, BasicBlock:ch<bb33.preheader 0x4255a68>, Constant:i8<3>, t25
  t26: i8 = Constant<3>
  t25: glue = CMP t8, Constant:i8<-64>
    t8: i8,ch = load<LD1[%v18]> t0, t5, undef:i16
      t5: i16 = add t2, t4
        t2: i16,ch = CopyFromReg t0, Register:i16 %vreg0
          t1: i16 = Register %vreg0
        t4: i16,ch = CopyFromReg t0, Register:i16 %vreg2
          t3: i16 = Register %vreg2
      t7: i16 = undef
    t21: i8 = Constant<-64>
In function: _ZN4core3str16slice_error_fail17ha9abe7236f6b8737E

Failing build

Trying to build avr-rust breaks whenever I run make.
The submodule src/llvm is hardcoded to use the commit cebc0b4:

# make
[...]
Synchronizing submodule url for 'src/llvm'
[...]
# cd src/llvm; git checkout
(HEAD detached at cebc0b4)

This seems to correspond to the branch avr-rust, and produces a broken build, in which the shl instruction is not lowered properly:

CFG_LLVM_LINKAGE_FILE= LD_LIBRARY_PATH=/mnt/tempcache/AVR-rust/avr-rust-build/x86_64-unknown-linux-gnu/stage2/lib:$LD_LIBRARY_PATH   x86_64-unknown-linux-gnu/stage2/bin/rustc --cfg stage2  -O --cfg rtopt  --target=avr-atmel-none -C linker=avr-gcc -C ar=avr-ar  -C target-cpu=atmega328p -C prefer-dynamic -D warnings -L "avr-atmel-none/rt"     --out-dir x86_64-unknown-linux-gnu/stage2/lib/rustlib/avr-atmel-none/lib -C extra-filename=-a5fc0d6c ../avr-rust/src/libcore/lib.rs
LLVM ERROR: Cannot select: 0x7f616b009818: i8 = ##name## 0x7f616be53ce8, 0x7f616b5d3b88 [ORD=4] [ID=8]
  0x7f616be53ce8: i8,ch = CopyFromReg 0x7f616b840d10, 0x7f6170529ce8 [ORD=1] [ID=5]
    0x7f6170529ce8: i8 = Register %vreg0 [ID=1]
  0x7f616b5d3b88: i16 = and 0x7f616b00a158, 0x7f6171ba5720 [ORD=4] [ID=7]
    0x7f616b00a158: i16,ch = CopyFromReg 0x7f616b840d10, 0x7f6171bd8a90 [ORD=1] [ID=6]
      0x7f6171bd8a90: i16 = Register %vreg1 [ID=2]
    0x7f6171ba5720: i16 = Constant<7> [ID=4]
In function: _ZN3num8wrapping35Wrapping$LT$u8$GT$.Shl$LT$usize$GT$3shl20h8e8197c1e2abaa89d3aE

As a related question, how to make sure llvm does not revert to some other branch when I do make?

Rework C-ABI translation

Looks like f0636b6 rewrote how all of the layout / alignment / LLVM type stuff is handled (insert handwaving here). I've had to completely comment it out to proceed with compilation, but I'm pretty sure any resulting compiler will be inoperable.

@dylanmckay I can push up (yet another) branch with this WIP if you'd be able to do that brain-thinking-thing you know how do to?

Assertion failed: (DstReg != SrcReg && "SrcReg and DstReg cannot be the same")

While compiling Rust libcore

I've got a (massive) testcase
libcore.ll. This is the entire Rust libcore as an LLVM IR program.

Reproduction

./bin/llc ~/libcore.ll -O0 -o /dev/null
Assertion failed: (DstReg != SrcReg && "SrcReg and DstReg cannot be the same"), function expand, file /Users/dylan/projects/llvm-project/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp, line 590.
0  libLLVMSupport.dylib     0x0000000111c333ac llvm::sys::PrintStackTrace(llvm::raw_ostream&) + 60
1  libLLVMSupport.dylib     0x0000000111c338f9 PrintStackTraceSignalHandler(void*) + 25
2  libLLVMSupport.dylib     0x0000000111c2fa29 llvm::sys::RunSignalHandlers() + 425
3  libLLVMSupport.dylib     0x0000000111c33c42 SignalHandler(int) + 354
4  libsystem_platform.dylib 0x00007fff925b6b3a _sigtramp + 26
5  libsystem_platform.dylib 0xffffffffffffffff _sigtramp + 1839502559
6  libsystem_c.dylib        0x00007fff9243b420 abort + 129
7  libsystem_c.dylib        0x00007fff92402893 basename_r + 0
8  libLLVMAVRCodeGen.dylib  0x000000010d4f73e5 bool (anonymous namespace)::AVRExpandPseudo::expand<184u>(llvm::MachineBasicBlock&, llvm::MachineInstrBundleIterator<llvm::MachineInstr, false>) + 277
9  libLLVMAVRCodeGen.dylib  0x000000010d4f4470 (anonymous namespace)::AVRExpandPseudo::expandMI(llvm::MachineBasicBlock&, llvm::MachineInstrBundleIterator<llvm::MachineInstr, false>) + 1184
10 libLLVMAVRCodeGen.dylib  0x000000010d4f3c7c (anonymous namespace)::AVRExpandPseudo::expandMBB(llvm::MachineBasicBlock&) + 316
11 libLLVMAVRCodeGen.dylib  0x000000010d4f36fa (anonymous namespace)::AVRExpandPseudo::runOnMachineFunction(llvm::MachineFunction&) + 298
12 libLLVMCodeGen.dylib     0x000000010ef26b51 llvm::MachineFunctionPass::runOnFunction(llvm::Function&) + 449
13 libLLVMCore.dylib        0x000000010ff3679f llvm::FPPassManager::runOnFunction(llvm::Function&) + 399
14 libLLVMCore.dylib        0x000000010ff36ca5 llvm::FPPassManager::runOnModule(llvm::Module&) + 117
15 libLLVMCore.dylib        0x000000010ff37a74 (anonymous namespace)::MPPassManager::runOnModule(llvm::Module&) + 2196
16 libLLVMCore.dylib        0x000000010ff36f66 llvm::legacy::PassManagerImpl::run(llvm::Module&) + 342
17 libLLVMCore.dylib        0x000000010ff387a1 llvm::legacy::PassManager::run(llvm::Module&) + 33
18 llc                      0x0000000108b462b2 compileModule(char**, llvm::LLVMContext&) + 21810
19 llc                      0x0000000108b4017f main + 2447
20 libdyld.dylib            0x00007fff923a7235 start + 1
Stack dump:
0.      Program arguments: ./bin/llc /Users/dylan/libcore.ll -O0 -o /dev/null
1.      Running pass 'Function Pass Manager' on module '/Users/dylan/libcore.ll'.
2.      Running pass 'AVR pseudo instruction expansion pass' on function '@_ZN4core4sync6atomic11atomic_load17h9977d1b8983da2bdE'
[1]    55133 abort      ./bin/llc ~/libcore.ll -O0 -o /dev/null

LLVM error when optimizations are turned off

When using rustc to compile for the AVR target, an LLVM error is generated:

LLVM ERROR: regalloc=... not currently supported with -O0

Which can be tracked back to llvm/lib/CodeGen/LiveVariables.cpp:635. There is a note at this line mentioning that this bug is an artifact of 'bizarre pass dependencies' and that it should be fixed. This leads me to believe that this error can be solved by either writing the fix specified on the aforementioned line, or simply changing the order in which Rust adds LLVM passes.

The AVR LLVM backend can successfully generate executables on its own (using llc), and so this bug must lay in Rust itself.

ResumeInst needs to be in a function with a personality

Trying to update to avr-llvm/llvm@3c0d2ad, I've made some good progress and some nasty hacks, but now I'm stuck at this intriguing LLVM error

ResumeInst needs to be in a function with a personality.
  resume { i8*, i32 } %3
LLVM ERROR: Broken function found, compilation aborted!

Unfortunately, I have not been able to generate an LLVM IR dump of the invalid input before the failure occurs, and I can't get useful debugging symbols in LLVM or add debugging prints to the LLVM codebase. Frustrating!

Investigate inclusion of `std` crate

Investigate the possibility of compiling the std crate for AVR. Obviously, much of the code would be unsupported (IO and the like), but perhaps a subset of the crate could be enabled.

Currently the average non-freestanding Rust executable is 900+ kilobytes. Perhaps the goal of including std is only possible on the day that Rust executables can be stripped of any and all unneeded code.

panic_bounds_check not found at link time

Again, using my own cut-down version of libcore, and the following program:

const SCREEN_WIDTH: u8 = 16;
const SCREEN_HEIGHT: u8 = 16;

static mut FB_PIXELS: [[u8; (SCREEN_HEIGHT / 8) as usize]; SCREEN_WIDTH as usize] = [[0; (SCREEN_HEIGHT / 8) as usize]; SCREEN_WIDTH as usize];

#[inline(never)]
fn set_pixel(x: u8, y: u8, v: bool) {
    let row = y >> 3;
    let offset = y - (row << 3);
    let mask = 1 << offset;
    let bit = (if v {1} else {0}) << offset;

    unsafe {
        FB_PIXELS[x as usize][row as usize] = (FB_PIXELS[x as usize][row as usize] & !mask) | bit;
    }
}

#[inline(never)]
fn draw_pattern() {
    for i in 0..9 {
        set_pixel(i, SCREEN_HEIGHT - (i + 1), false);
    }
}

#[no_mangle]
pub extern fn main() {
    draw_pattern();
    loop {}
}

(again, if really needed, I can try scraping together the libcore I use in some format that I can provide the full program).

My modest version of panic_bounds_check is:

#[cold] #[inline(never)]
#[lang = "panic_bounds_check"]
pub fn panic_bounds_check(file_line: &(&'static str, u32),
                     index: usize, len: usize) -> ! {
    loop {}
}

I haven't managed to get linking working with cargo, so I am linking manually. The problem is that panic_bounds_check is not found by the linker:

$ avr-gcc -Os -Wl,--gc-sections -mmcu=atmega328p -o target/avr-atmega328p/release/image.elf target/avr-atmega328p/release/deps/bounds_panic-bafa1b16b1f84a16.o 
target/avr-atmega328p/release/deps/bounds_panic-bafa1b16b1f84a16.o: In function `LBB1_5':
bounds_panic.cgu-0.rs:(.text._ZN12bounds_panic9set_pixel17hb225fcaa63bbc51eE+0x4a): undefined reference to `libcore_mini::panicking::panic_bounds_check::h201496b58059e323'
target/avr-atmega328p/release/deps/bounds_panic-bafa1b16b1f84a16.o: In function `LBB1_6':
bounds_panic.cgu-0.rs:(.text._ZN12bounds_panic9set_pixel17hb225fcaa63bbc51eE+0x5a): undefined reference to `libcore_mini::panicking::panic_bounds_check::h201496b58059e323'
collect2: error: ld returned 1 exit status

Full LLVM IR dump:

; ModuleID = 'bounds_panic.cgu-0.rs'
source_filename = "bounds_panic.cgu-0.rs"
target datalayout = "e-p:16:16:16-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-n8"
target triple = "avr-atmel-none"

%str_slice = type { i8*, i16 }

@_ZN12bounds_panic9FB_PIXELS17h187da639c865323bE = internal unnamed_addr global [16 x [2 x i8]] zeroinitializer, align 1
@str.0 = internal constant [11 x i8] c"src/main.rs"
@panic_bounds_check_loc.1 = internal unnamed_addr constant { %str_slice, i32 } { %str_slice { i8* getelementptr inbounds ([11 x i8], [11 x i8]* @str.0, i32 0, i32 0), i16 11 }, i32 47 }, align 4

; Function Attrs: norecurse nounwind readnone uwtable
define void @rust_eh_personality({}* nocapture, {}* nocapture) unnamed_addr #0 {
start:
  ret void
}

; Function Attrs: noinline uwtable
define internal fastcc void @_ZN12bounds_panic9set_pixel17hb225fcaa63bbc51eE(i8, i8) unnamed_addr #1 {
start:
  %2 = and i8 %1, 7
  %3 = shl i8 1, %2
  %4 = zext i8 %0 to i16
  %5 = icmp ult i8 %0, 16
  br i1 %5, label %bb4, label %panic, !prof !1

bb4:                                              ; preds = %start
  %6 = lshr i8 %1, 3
  %7 = zext i8 %6 to i16
  %8 = icmp ult i8 %1, 16
  br i1 %8, label %bb5, label %panic1, !prof !1

bb5:                                              ; preds = %bb4
  %9 = getelementptr inbounds [16 x [2 x i8]], [16 x [2 x i8]]* @_ZN12bounds_panic9FB_PIXELS17h187da639c865323bE, i16 0, i16 %4, i16 %7
  %10 = load i8, i8* %9, align 1
  %11 = xor i8 %3, -1
  %12 = and i8 %10, %11
  store i8 %12, i8* %9, align 1
  ret void

panic:                                            ; preds = %start
  tail call void @_ZN12libcore_mini9panicking18panic_bounds_check17h201496b58059e323E({ %str_slice, [0 x i8], i32, [0 x i8] }* bitcast ({ %str_slice, i32 }* @panic_bounds_check_loc.1 to { %str_slice, [0 x i8], i32, [0 x i8] }*), i16 %4, i16 16)
  unreachable

panic1:                                           ; preds = %bb4
  tail call void @_ZN12libcore_mini9panicking18panic_bounds_check17h201496b58059e323E({ %str_slice, [0 x i8], i32, [0 x i8] }* bitcast ({ %str_slice, i32 }* @panic_bounds_check_loc.1 to { %str_slice, [0 x i8], i32, [0 x i8] }*), i16 %7, i16 2)
  unreachable
}

; Function Attrs: noinline uwtable
define internal fastcc void @_ZN12bounds_panic12draw_pattern17he46f0b4d7b24326cE() unnamed_addr #1 personality void ({}*, {}*)* @rust_eh_personality {
start:
  tail call fastcc void @_ZN12bounds_panic9set_pixel17hb225fcaa63bbc51eE(i8 0, i8 15)
  tail call fastcc void @_ZN12bounds_panic9set_pixel17hb225fcaa63bbc51eE(i8 1, i8 14)
  tail call fastcc void @_ZN12bounds_panic9set_pixel17hb225fcaa63bbc51eE(i8 2, i8 13)
  tail call fastcc void @_ZN12bounds_panic9set_pixel17hb225fcaa63bbc51eE(i8 3, i8 12)
  tail call fastcc void @_ZN12bounds_panic9set_pixel17hb225fcaa63bbc51eE(i8 4, i8 11)
  tail call fastcc void @_ZN12bounds_panic9set_pixel17hb225fcaa63bbc51eE(i8 5, i8 10)
  tail call fastcc void @_ZN12bounds_panic9set_pixel17hb225fcaa63bbc51eE(i8 6, i8 9)
  tail call fastcc void @_ZN12bounds_panic9set_pixel17hb225fcaa63bbc51eE(i8 7, i8 8)
  tail call fastcc void @_ZN12bounds_panic9set_pixel17hb225fcaa63bbc51eE(i8 8, i8 7)
  ret void
}

; Function Attrs: noreturn nounwind uwtable
define void @main() unnamed_addr #2 {
start:
  tail call fastcc void @_ZN12bounds_panic12draw_pattern17he46f0b4d7b24326cE() #4
  br label %bb1

bb1:                                              ; preds = %bb1, %start
  br label %bb1
}

; Function Attrs: cold noinline noreturn
declare void @_ZN12libcore_mini9panicking18panic_bounds_check17h201496b58059e323E({ %str_slice, [0 x i8], i32, [0 x i8] }* noalias readonly dereferenceable(8), i16, i16) unnamed_addr #3

attributes #0 = { norecurse nounwind readnone uwtable }
attributes #1 = { noinline uwtable }
attributes #2 = { noreturn nounwind uwtable }
attributes #3 = { cold noinline noreturn }
attributes #4 = { nounwind }

!llvm.module.flags = !{!0}

!0 = !{i32 1, !"PIE Level", i32 2}
!1 = !{!"branch_weights", i32 2000, i32 1}

Add `volatile` block to Rust's syntax

It may be a good idea to add a volatile block to Rust's syntax, similar to unsafe.

fn main() {
    unsafe {
        volatile {
            *0x20 = 0b11001010;
        }
    }
}

To make this even better, it could be possible to do something like so, to avoid the messy nested unsafe and volatile blocks:

fn main() {
    unsafe volatile {
        *0x20 = 0b11001010;
    }
}

Assertion failed: (MI && "No instruction defining live value"), function computeDeadValues

A reproduction:

; ModuleID = 'bugpoint-reduced-simplified.bc'
source_filename = "bugpoint-output-016b51a.bc"
target datalayout = "e-p:16:16:16-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-n8"
target triple = "avr-atmel-none"

%"num::bignum::Big32x40.ALPHA.0.9.10.15.16.17.18.22.27.31.32.36.38.49.64.71.85.88.93.98.100.0.10.12.14.15.16.19.25.26.28.33.34.35.48.63.74.79.88.93.107.119" = type { i16, [2 x i8], [40 x i32], [0 x i8] }

@core_num_flt2dec_strategy_dragon_POW10TO128 = external constant [14 x i32], align 4

define nonnull dereferenceable(164) %"num::bignum::Big32x40.ALPHA.0.9.10.15.16.17.18.22.27.31.32.36.38.49.64.71.85.88.93.98.100.0.10.12.14.15.16.19.25.26.28.33.34.35.48.63.74.79.88.93.107.119"* @core_num_flt2dec_strategy_dragon(%"num::bignum::Big32x40.ALPHA.0.9.10.15.16.17.18.22.27.31.32.36.38.49.64.71.85.88.93.98.100.0.10.12.14.15.16.19.25.26.28.33.34.35.48.63.74.79.88.93.107.119"* returned dereferenceable(164), i16) unnamed_addr {
start:
  %ret.i = alloca [40 x i32], align 4
  %2 = icmp eq i16 undef, 0
  br i1 %2, label %bb5, label %bb1

bb1:                                              ; preds = %start
  unreachable

bb5:                                              ; preds = %start
  br i1 undef, label %bb14, label %bb11

bb11:                                             ; preds = %bb5
  unreachable

bb14:                                             ; preds = %bb5
  %3 = bitcast [40 x i32]* %ret.i to i8*
  call void @llvm.memset.p0i8.i16(i8* nonnull %3, i8 0, i16 160, i32 4, i1 false)
  %4 = getelementptr inbounds %"num::bignum::Big32x40.ALPHA.0.9.10.15.16.17.18.22.27.31.32.36.38.49.64.71.85.88.93.98.100.0.10.12.14.15.16.19.25.26.28.33.34.35.48.63.74.79.88.93.107.119", %"num::bignum::Big32x40.ALPHA.0.9.10.15.16.17.18.22.27.31.32.36.38.49.64.71.85.88.93.98.100.0.10.12.14.15.16.19.25.26.28.33.34.35.48.63.74.79.88.93.107.119"* %0, i16 0, i32 0
  %5 = load i16, i16* %4, align 2
  %6 = icmp ult i16 %5, 14
  %7 = getelementptr inbounds %"num::bignum::Big32x40.ALPHA.0.9.10.15.16.17.18.22.27.31.32.36.38.49.64.71.85.88.93.98.100.0.10.12.14.15.16.19.25.26.28.33.34.35.48.63.74.79.88.93.107.119", %"num::bignum::Big32x40.ALPHA.0.9.10.15.16.17.18.22.27.31.32.36.38.49.64.71.85.88.93.98.100.0.10.12.14.15.16.19.25.26.28.33.34.35.48.63.74.79.88.93.107.119"* %0, i16 0, i32 2, i16 0
  br i1 %6, label %bb2.i38, label %bb3.i39

bb2.i38:                                          ; preds = %bb14
  %8 = getelementptr inbounds %"num::bignum::Big32x40.ALPHA.0.9.10.15.16.17.18.22.27.31.32.36.38.49.64.71.85.88.93.98.100.0.10.12.14.15.16.19.25.26.28.33.34.35.48.63.74.79.88.93.107.119", %"num::bignum::Big32x40.ALPHA.0.9.10.15.16.17.18.22.27.31.32.36.38.49.64.71.85.88.93.98.100.0.10.12.14.15.16.19.25.26.28.33.34.35.48.63.74.79.88.93.107.119"* %0, i16 0, i32 2, i16 %5
  %9 = ptrtoint i32* %7 to i16
  br label %bb4.outer.i122

bb4.outer.i122:                                   ; preds = %bb24.i141, %bb2.i38
  %iter.sroa.0.0.ph.i119 = phi i16 [ %13, %bb24.i141 ], [ %9, %bb2.i38 ]
  %retsz.0.ph.i121 = phi i16 [ %.retsz.0.i140, %bb24.i141 ], [ 0, %bb2.i38 ]
  br label %bb4.i125

bb4.i125:                                         ; preds = %core.iter.Enumerate.ALPHA, %bb4.outer.i122
  %iter.sroa.0.0.i123 = phi i16 [ %13, %core.iter.Enumerate.ALPHA ], [ %iter.sroa.0.0.ph.i119, %bb4.outer.i122 ]
  %10 = inttoptr i16 %iter.sroa.0.0.i123 to i32*
  %11 = icmp eq i32* %10, %8
  br i1 %11, label %core.num.bignum.Big32x40.exit44, label %core.iter.Enumerate.ALPHA

core.iter.Enumerate.ALPHA:                        ; preds = %bb4.i125
  %12 = getelementptr inbounds i32, i32* %10, i16 1
  %13 = ptrtoint i32* %12 to i16
  %14 = load i32, i32* %10, align 4
  %15 = icmp eq i32 %14, 0
  br i1 %15, label %bb4.i125, label %core..iter..Enumerate.exit17

core..iter..Enumerate.exit17:                     ; preds = %core.iter.Enumerate.ALPHA
  %16 = zext i32 %14 to i64
  br label %core..iter..Enumerate.exit17.i132

core..iter..Enumerate.exit17.i132:                ; preds = %core_slice_IndexMut.exit13, %core..iter..Enumerate.exit17
  %carry.085.i129 = phi i32 [ 0, %core..iter..Enumerate.exit17 ], [ %29, %core_slice_IndexMut.exit13 ]
  %17 = icmp ult i16 undef, 40
  br i1 %17, label %core_slice_IndexMut.exit13, label %panic.i.i14.i134

bb16.i133:                                        ; preds = %core_slice_IndexMut.exit13
  %18 = icmp eq i32 %29, 0
  br i1 %18, label %bb24.i141, label %bb21.i136

panic.i.i14.i134:                                 ; preds = %core..iter..Enumerate.exit17.i132
  unreachable

core_slice_IndexMut.exit13:                       ; preds = %core..iter..Enumerate.exit17.i132
  %19 = load i32, i32* null, align 4
  %20 = getelementptr inbounds [40 x i32], [40 x i32]* %ret.i, i16 0, i16 undef
  %21 = load i32, i32* %20, align 4
  %22 = zext i32 %19 to i64
  %23 = mul nuw i64 %22, %16
  %24 = zext i32 %21 to i64
  %25 = zext i32 %carry.085.i129 to i64
  %26 = add nuw nsw i64 %24, %25
  %27 = add i64 %26, %23
  %28 = lshr i64 %27, 32
  %29 = trunc i64 %28 to i32
  %30 = icmp eq i32* undef, getelementptr inbounds ([14 x i32], [14 x i32]* @core_num_flt2dec_strategy_dragon_POW10TO128, i16 1, i16 0)
  br i1 %30, label %bb16.i133, label %core..iter..Enumerate.exit17.i132

bb21.i136:                                        ; preds = %bb16.i133
  %31 = icmp ult i16 undef, 40
  br i1 %31, label %"_ZN4core5slice70_$LT$impl$u20$core..ops..IndexMut$LT$I$GT$$u20$for$u20$$u5b$T$u5d$$GT$9index_mut17h8eccc0af1ec6f971E.exit.i138", label %panic.i.i.i137

panic.i.i.i137:                                   ; preds = %bb21.i136
  unreachable

"_ZN4core5slice70_$LT$impl$u20$core..ops..IndexMut$LT$I$GT$$u20$for$u20$$u5b$T$u5d$$GT$9index_mut17h8eccc0af1ec6f971E.exit.i138": ; preds = %bb21.i136
  store i32 %29, i32* undef, align 4
  br label %bb24.i141

bb24.i141:                                        ; preds = %"_ZN4core5slice70_$LT$impl$u20$core..ops..IndexMut$LT$I$GT$$u20$for$u20$$u5b$T$u5d$$GT$9index_mut17h8eccc0af1ec6f971E.exit.i138", %bb16.i133
  %sz.0.i139 = phi i16 [ 15, %"_ZN4core5slice70_$LT$impl$u20$core..ops..IndexMut$LT$I$GT$$u20$for$u20$$u5b$T$u5d$$GT$9index_mut17h8eccc0af1ec6f971E.exit.i138" ], [ 14, %bb16.i133 ]
  %32 = add i16 %sz.0.i139, 0
  %33 = icmp ult i16 %retsz.0.ph.i121, %32
  %.retsz.0.i140 = select i1 %33, i16 %32, i16 %retsz.0.ph.i121
  br label %bb4.outer.i122

bb3.i39:                                          ; preds = %bb14
  %34 = call fastcc i16 @_ZN4core3num6bignum8Big32x4010mul_digits9mul_inner17h5d3461bce04d16ccE([40 x i32]* nonnull dereferenceable(160) %ret.i, i32* noalias nonnull readonly getelementptr inbounds ([14 x i32], [14 x i32]* @core_num_flt2dec_strategy_dragon_POW10TO128, i16 0, i16 0), i16 14, i32* noalias nonnull readonly %7, i16 %5)
  br label %core.num.bignum.Big32x40.exit44

core.num.bignum.Big32x40.exit44:                  ; preds = %bb3.i39, %bb4.i125
  %retsz.0.i40 = phi i16 [ %34, %bb3.i39 ], [ %retsz.0.ph.i121, %bb4.i125 ]
  call void @llvm.memcpy.p0i8.p0i8.i16(i8* undef, i8* nonnull %3, i16 160, i32 4, i1 false)
  store i16 %retsz.0.i40, i16* %4, align 2
  %35 = and i16 %1, 256
  %36 = icmp eq i16 %35, 0
  br i1 %36, label %bb30, label %bb27

bb27:                                             ; preds = %core.num.bignum.Big32x40.exit44
  unreachable

bb30:                                             ; preds = %core.num.bignum.Big32x40.exit44
  ret %"num::bignum::Big32x40.ALPHA.0.9.10.15.16.17.18.22.27.31.32.36.38.49.64.71.85.88.93.98.100.0.10.12.14.15.16.19.25.26.28.33.34.35.48.63.74.79.88.93.107.119"* %0
}

declare fastcc i16 @_ZN4core3num6bignum8Big32x4010mul_digits9mul_inner17h5d3461bce04d16ccE([40 x i32]* nocapture dereferenceable(160), i32* noalias nonnull readonly, i16, i32* noalias nonnull readonly, i16) unnamed_addr

; Function Attrs: argmemonly nounwind
declare void @llvm.memset.p0i8.i16(i8* nocapture writeonly, i8, i16, i32, i1) #0

; Function Attrs: argmemonly nounwind
declare void @llvm.memcpy.p0i8.p0i8.i16(i8* nocapture writeonly, i8* nocapture readonly, i16, i32, i1) #0

attributes #0 = { argmemonly nounwind }
Original
; ModuleID = 'bugpoint-reduced-simplified.bc'
source_filename = "bugpoint-output-7b72b44.bc"
target datalayout = "e-p:16:16:16-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-n8"
target triple = "avr"

%BN1.0.5.14.17.18.19.21.26.29.31.34.40.42.57.71.80.84.89.91.95.105 = type { i16, [2 x i8], [40 x i32], [0 x i8] }

@DragonCodeAlpha = external constant [14 x i32], align 4

; Function Attrs: uwtable
define nonnull dereferenceable(164) %BN1.0.5.14.17.18.19.21.26.29.31.34.40.42.57.71.80.84.89.91.95.105* @DragonAlpha(%BN1.0.5.14.17.18.19.21.26.29.31.34.40.42.57.71.80.84.89.91.95.105* returned dereferenceable(164), i16) unnamed_addr #0 personality i32 (...)* @rust_eh_personality {
start:
  %ret.i = alloca [40 x i32], align 4
  br i1 undef, label %bb5, label %bb1

bb1:                                              ; preds = %start
  unreachable

bb5:                                              ; preds = %start
  %2 = icmp eq i16 undef, 0
  br i1 %2, label %bb10, label %bb8

bb8:                                              ; preds = %bb5
  unreachable

bb10:                                             ; preds = %bb5
  %3 = bitcast [40 x i32]* %ret.i to i8*
  %4 = load i16, i16* undef, align 2
  %5 = getelementptr inbounds %BN1.0.5.14.17.18.19.21.26.29.31.34.40.42.57.71.80.84.89.91.95.105, %BN1.0.5.14.17.18.19.21.26.29.31.34.40.42.57.71.80.84.89.91.95.105* %0, i16 0, i32 2, i16 0
  br i1 undef, label %bb2.i38, label %bb3.i39

bb2.i38:                                          ; preds = %bb10
  %6 = getelementptr inbounds %BN1.0.5.14.17.18.19.21.26.29.31.34.40.42.57.71.80.84.89.91.95.105, %BN1.0.5.14.17.18.19.21.26.29.31.34.40.42.57.71.80.84.89.91.95.105* %0, i16 0, i32 2, i16 %4
  br label %bb4.outer.i122

bb4.outer.i122:                                   ; preds = %bb24.i141, %bb2.i38
  %iter.sroa.7.0.ph.i120 = phi i16 [ %8, %bb24.i141 ], [ 0, %bb2.i38 ]
  %retsz.0.ph.i121 = phi i16 [ %.retsz.0.i140, %bb24.i141 ], [ 0, %bb2.i38 ]
  br label %bb4.i125

bb4.i125:                                         ; preds = %EnumerateAlpha, %bb4.outer.i122
  %iter.sroa.7.0.i124 = phi i16 [ %8, %EnumerateAlpha ], [ %iter.sroa.7.0.ph.i120, %bb4.outer.i122 ]
  %7 = icmp eq i32* undef, %6
  br i1 %7, label %_ZN4core3num6bignum8Big32x4010mul_digits17hb016ab455b44b71bE.exit44, label %EnumerateAlpha

EnumerateAlpha:                                   ; preds = %bb4.i125
  %8 = add i16 %iter.sroa.7.0.i124, 1
  %9 = icmp eq i32 undef, 0
  br i1 %9, label %bb4.i125, label %EnumerateBeta

EnumerateBeta:                                    ; preds = %EnumerateAlpha
  %10 = zext i32 undef to i64
  br label %EnumerateGamma

EnumerateGamma:                                   ; preds = %EnumerateBeta
  %11 = icmp ult i16 undef, 40
  br i1 %11, label %SliceMutAlpha, label %panic.i.i14.i134, !prof !0

bb16.i133:                                        ; preds = %SliceMutAlpha
  br i1 undef, label %bb24.i141, label %bb21.i136

panic.i.i14.i134:                                 ; preds = %EnumerateGamma
  unreachable

SliceMutAlpha:                                    ; preds = %EnumerateGamma
  %12 = load i32, i32* undef, align 4, !alias.scope !1, !noalias !4
  %13 = zext i32 %12 to i64
  %14 = mul nuw i64 %13, %10
  %15 = add i64 0, %14
  %16 = lshr i64 %15, 32
  %17 = trunc i64 %15 to i32
  store i32 %17, i32* undef, align 4, !noalias !6
  br label %bb16.i133

bb21.i136:                                        ; preds = %bb16.i133
  br i1 undef, label %SliceMutBeta, label %panic.i.i.i137, !prof !0

panic.i.i.i137:                                   ; preds = %bb21.i136
  unreachable

SliceMutBeta:                                     ; preds = %bb21.i136
  br label %bb24.i141

bb24.i141:                                        ; preds = %SliceMutBeta, %bb16.i133
  %18 = add i16 0, %iter.sroa.7.0.i124
  %19 = icmp ult i16 %retsz.0.ph.i121, %18
  %.retsz.0.i140 = select i1 %19, i16 %18, i16 %retsz.0.ph.i121
  br label %bb4.outer.i122

bb3.i39:                                          ; preds = %bb10
  %20 = call fastcc i16 @BignumInnerAlpha([40 x i32]* nonnull dereferenceable(160) %ret.i, i32* noalias nonnull readonly getelementptr inbounds ([14 x i32], [14 x i32]* @DragonCodeAlpha, i16 0, i16 0), i16 14, i32* noalias nonnull readonly %5, i16 %4)
  br label %_ZN4core3num6bignum8Big32x4010mul_digits17hb016ab455b44b71bE.exit44

_ZN4core3num6bignum8Big32x4010mul_digits17hb016ab455b44b71bE.exit44: ; preds = %bb3.i39, %bb4.i125
  %retsz.0.i40 = phi i16 [ %20, %bb3.i39 ], [ %retsz.0.ph.i121, %bb4.i125 ]
  %21 = getelementptr inbounds %BN1.0.5.14.17.18.19.21.26.29.31.34.40.42.57.71.80.84.89.91.95.105, %BN1.0.5.14.17.18.19.21.26.29.31.34.40.42.57.71.80.84.89.91.95.105* %0, i16 0, i32 2
  %22 = bitcast [40 x i32]* %21 to i8*
  call void @llvm.memcpy.p0i8.p0i8.i16(i8* %22, i8* nonnull %3, i16 160, i32 4, i1 false), !noalias !7
  store i16 %retsz.0.i40, i16* undef, align 2, !noalias !7
  %23 = and i16 %1, 256
  %24 = icmp eq i16 %23, 0
  br i1 %24, label %bb30, label %bb27

bb27:                                             ; preds = %_ZN4core3num6bignum8Big32x4010mul_digits17hb016ab455b44b71bE.exit44
  unreachable

bb30:                                             ; preds = %_ZN4core3num6bignum8Big32x4010mul_digits17hb016ab455b44b71bE.exit44
  ret %BN1.0.5.14.17.18.19.21.26.29.31.34.40.42.57.71.80.84.89.91.95.105* %0
}

; Function Attrs: uwtable
declare fastcc i16 @BignumInnerAlpha([40 x i32]* nocapture dereferenceable(160), i32* noalias nonnull readonly, i16, i32* noalias nonnull readonly, i16) unnamed_addr #0

; Function Attrs: argmemonly nounwind
declare void @llvm.memcpy.p0i8.p0i8.i16(i8* nocapture writeonly, i8* nocapture readonly, i16, i32, i1) #1

declare i32 @rust_eh_personality(...) unnamed_addr

attributes #0 = { uwtable }
attributes #1 = { argmemonly nounwind }

!0 = !{!"branch_weights", i32 2000, i32 1}
!1 = !{!2}
!2 = distinct !{!2, !3, !"BignumInnerAlpha: argument 1"}
!3 = distinct !{!3, !"BignumInnerAlpha"}
!4 = !{!5}
!5 = distinct !{!5, !3, !"BignumInnerAlpha: argument 0"}
!6 = !{!5, !2}
!7 = !{!8}
!8 = distinct !{!8, !9, !"_ZN4core3num6bignum8Big32x4010mul_digits17hb016ab455b44b71bE: argument 0"}
!9 = distinct !{!9, !"_ZN4core3num6bignum8Big32x4010mul_digits17hb016ab455b44b71bE"}

no_std problem

I build the compiler and tried to run an example, but I got following error:

main.rs:4:1: 4:11 error: no_std is experimental
 main.rs:4 #![no_std]
 main.rs:4:11: 4:11 help: add #![feature(no_std)] to the crate attributes to enable

Adding #![feature(no_std)] makes the compiler complain about not finding built-in types:
 main.rs:13:21: 13:25 error: use of undeclared type name `uint`
 main.rs:13 const __SFR_OFFSET: uint = 0x20;
 main.rs:36:12: 36:15 error: use of undeclared type name `int`
 main.rs:36 fn main(_: int, _: *const *const u8) -> int {
 main.rs:36:41: 36:44 error: use of undeclared type name `int`
 main.rs:36 fn main(_: int, _: *const *const u8) -> int {

Assertion failed: (!SplitVirtReg->empty() && "expecting non-empty interval"), function allocatePhysRegs

I commented out all the bignum / dec2flt / flt2dec / diyfloat modules and got to this error.

; ModuleID = 'bugpoint-reduced-simplified.bc'
source_filename = "bugpoint-output-9da0630.bc"
target datalayout = "e-p:16:16:16-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-n8"
target triple = "avr"

; Function Attrs: uwtable
define fastcc void @_ZN4core3num14from_str_radix17h52611b1bf2950c2eE(i8* noalias nonnull readonly, i16, i32) unnamed_addr #0 {
start:
  %not. = icmp ugt i32 undef, 34
  br i1 %not., label %bb5, label %bb6

bb5:                                              ; preds = %start
  unreachable

bb6:                                              ; preds = %start
  %3 = load i8, i8* %0, align 1
  switch i8 %3, label %SliceAlpha [
    i8 43, label %bb23
    i8 45, label %SliceIndexAlpha
  ]

bb13.loopexit:                                    ; preds = %bb12.i49
  unreachable

bb13.loopexit150:                                 ; preds = %bb61, %bb57, %bb12.i
  %.sink121.ph151 = phi i8 [ 3, %bb61 ], [ 3, %bb57 ], [ 1, %bb12.i ]
  store i8 %.sink121.ph151, i8* undef, align 1
  unreachable

SliceAlpha:                                       ; preds = %bb6
  unreachable

SliceIndexAlpha:                                  ; preds = %bb6
  br label %bb23

bb23:                                             ; preds = %SliceIndexAlpha, %bb6
  %.sink15 = phi i1 [ false, %SliceIndexAlpha ], [ true, %bb6 ]
  %.sink12 = getelementptr inbounds i8, i8* %0, i16 1
  br label %bb28

bb28:                                             ; preds = %bb23
  br i1 %.sink15, label %SliceBeta, label %SliceGamma

SliceBeta:                                        ; preds = %bb28
  %4 = load i8, i8* %.sink12, align 1
  %5 = zext i8 %4 to i32
  br label %bb12.i49

SliceGamma:                                       ; preds = %bb28
  %.ptr136 = getelementptr inbounds i8, i8* %0, i16 %1
  br label %SliceTheta

bb12.i49:                                         ; preds = %SliceBeta
  %6 = add nsw i32 -48, %5
  %7 = icmp ult i32 %6, %2
  br i1 %7, label %bb40, label %bb13.loopexit

bb40:                                             ; preds = %bb12.i49
  unreachable

SliceTheta:                                       ; preds = %bb65, %SliceGamma
  %result.1134 = phi i128 [ %17, %bb65 ], [ 0, %SliceGamma ]
  %iter1.sroa.0.0.in133 = phi i8* [ %8, %bb65 ], [ %.sink12, %SliceGamma ]
  %8 = getelementptr inbounds i8, i8* %iter1.sroa.0.0.in133, i16 1
  br label %bb12.i

bb12.i:                                           ; preds = %SliceTheta
  %9 = add nsw i32 undef, undef
  %10 = icmp ult i32 %9, %2
  br i1 %10, label %bb57, label %bb13.loopexit150

bb57:                                             ; preds = %bb12.i
  %11 = tail call { i128, i1 } @llvm.smul.with.overflow.i128(i128 %result.1134, i128 undef) #2
  %12 = extractvalue { i128, i1 } %11, 1
  br i1 %12, label %bb13.loopexit150, label %bb61

bb61:                                             ; preds = %bb57
  %13 = extractvalue { i128, i1 } %11, 0
  %14 = zext i32 %9 to i128
  %15 = tail call { i128, i1 } @llvm.ssub.with.overflow.i128(i128 %13, i128 %14) #2
  %16 = extractvalue { i128, i1 } %15, 1
  br i1 %16, label %bb13.loopexit150, label %bb65

bb65:                                             ; preds = %bb61
  %17 = extractvalue { i128, i1 } %15, 0
  %18 = icmp eq i8* %8, %.ptr136
  br i1 %18, label %bb66.loopexit152, label %SliceTheta

bb66.loopexit152:                                 ; preds = %bb65
  unreachable
}

; Function Attrs: nounwind readnone
declare { i128, i1 } @llvm.ssub.with.overflow.i128(i128, i128) #1

; Function Attrs: nounwind readnone
declare { i128, i1 } @llvm.smul.with.overflow.i128(i128, i128) #1

attributes #0 = { uwtable }
attributes #1 = { nounwind readnone }
attributes #2 = { nounwind }

Arbitrary-bit rotations are not implemented

For this one, I don't have a nice small test case :( Full LLVM IR is at https://gist.github.com/gergoerdi/9f41a400d7611f7577cc83decf2dbbd4
The error message is:

LLVM ERROR: Cannot select: t44: i8 = rotl Constant:i8<-2>, t17
  t43: i8 = Constant<-2>
  t17: i8 = and t11, Constant:i8<7>
    t11: i8 = add t8, t10
      t8: i8,ch = CopyFromReg t0, Register:i8 %vreg6
        t7: i8 = Register %vreg6
      t10: i8,ch = CopyFromReg t0, Register:i8 %vreg23
        t9: i8 = Register %vreg23
    t16: i8 = Constant<7>
In function: main

Missing compiler-rt commit

It looks like there's a commit in compiler-rt which isn't published? I can't fetch the submodule.

error: no such remote ref 91f0fe0e367edd404ec5576bab070abb92333db9
Fetched in submodule path 'src/compiler-rt', but it did not contain 91f0fe0e367edd404ec5576bab070abb92333db9. Direct fetching of that commit failed.

IL ordering bug?

avrio.c.txt
avrio.ll.txt
blink.s.txt

look at how the pinMode function from avrio.ll gets converted into assembly in blink.s...

It looks like the last bit of the function in IL...

if.then2:                                         ; preds = %if.end
  %.sink30 = select i1 %cmp.i, i8* inttoptr (i16 42 to i8*), i8* inttoptr (i16 36 to i8*)
  %0 = load volatile i8, i8* %.sink30, align 2, !tbaa !1
  %or10 = or i8 %0, %conv3.i
  br label %if.end28

if.else13:                                        ; preds = %if.end
  %neg = xor i8 %conv3.i, -1
  %.sink32 = select i1 %cmp.i, i8* inttoptr (i16 42 to i8*), i8* inttoptr (i16 36 to i8*)
  %1 = load volatile i8, i8* %.sink32, align 2, !tbaa !1
  %and25 = and i8 %1, %neg
  br label %if.end28

if.end28:                                         ; preds = %if.else13, %if.then2
  %and25.sink.off0 = phi i8 [ %and25, %if.else13 ], [ %or10, %if.then2 ]
  %.sink32.sink = phi i8* [ %.sink32, %if.else13 ], [ %.sink30, %if.then2 ]
  store volatile i8 %and25.sink.off0, i8* %.sink32.sink, align 1, !tbaa !1
  br label %cleanup

cleanup:                                          ; preds = %if.else.i, %pinMask.exit, %if.end28
  ret void
}

Gets translated into assembly in the final product like this...

0000018c <LBB2_12>:
 18c:	b0 e0       	ldi	r27, 0x00	; 0
 18e:	8c 91       	ld	r24, X
 190:	82 2b       	or	r24, r18
 192:	28 2f       	mov	r18, r24
 194:	2c 93       	st	X, r18

00000196 <LBB2_14>:
 196:	df 91       	pop	r29
 198:	cf 91       	pop	r28
 19a:	08 95       	ret

0000019c <LBB2_15>:
 19c:	aa e2       	ldi	r26, 0x2A	; 42

0000019e <LBB2_16>:
 19e:	b0 e0       	ldi	r27, 0x00	; 0
 1a0:	8c 91       	ld	r24, X
 1a2:	20 95       	com	r18
 1a4:	28 23       	and	r18, r24

000001a6 <exit>:
 1a6:	f8 94       	cli
 1a8:	00 c0       	rjmp	.+0      	; 0x1aa <_exit>

000001aa <_exit>:
 1aa:	f8 94       	cli

The issue is that in the AND case, the st X, r18 instruction seems to be missing. Worse still, there's no jump back to LBB2_14, meaning that in this case the function won't even complete and the program will just fall through to the "exit" code instead.

Unable to compile dependency-free bare-bones example - unsupported instruction MCInst 157

Forgive me if the code below makes no sense; I'm kind of wildly experimenting to get something that works. Since libcore doesn't compile, I'm trying this example file:

#![feature(no_std)]
#![feature(no_core)]
#![feature(lang_items)]
#![feature(fundamental)]

#![no_std]
#![no_core]
#![no_main]

const PORTB: *mut u8 = 0x25 as *mut u8;

#[no_mangle]
pub extern fn main(_argc: i32, _argv: *const *const u8) -> i32 {
    loop {
        unsafe {
            *PORTB |= 0x1;
        }
    }
}

#[lang = "sized"]
#[fundamental]
pub trait Sized {}

#[lang = "copy"]
pub trait Copy : Clone {}

pub trait Clone : Sized {
    fn clone(&self) -> Self;

    #[inline(always)]
    fn clone_from(&mut self, source: &Self) {
        *self = source.clone()
    }
}

Compiled with rustc --target avr-atmel-none hello.rs yields:

'generic' is not a recognized processor for this target (ignoring processor)
LLVM ERROR: Not supported instr: <MCInst 157 <MCOperand Reg:51> <MCOperand Imm:11> <MCOperand Reg:49>>

The intermediate LLVM IR is

; ModuleID = 'hello.0.rs'
target datalayout = "e-p:16:8:8-i8:8:8-i16:8:8-i32:8:8-i64:8:8-f32:8:8-f64:8:8-n8"
target triple = "avr-atmel-none"

@const141 = internal unnamed_addr constant i8* inttoptr (i16 37 to i8*)
@const142 = internal unnamed_addr constant i8 1

define i32 @main(i32, i8**) unnamed_addr {
"the block":
  %2 = alloca i32
  store i32 %0, i32* %2
  %3 = load i32, i32* %2
  %4 = alloca i8**
  store i8** %1, i8*** %4
  %5 = load i8**, i8*** %4
  %6 = call i32 @_ZN4main10__rust_abiE(i32 %3, i8** %5)
  ret i32 %6
}

; Function Attrs: uwtable
define internal i32 @_ZN4main10__rust_abiE(i32, i8**) unnamed_addr #0 {
entry-block:
  %sret_slot = alloca i32
  %dropflag_hint_11 = alloca i8
  %dropflag_hint_14 = alloca i8
  %_argc = alloca i32
  %_argv = alloca i8**
  store i8 61, i8* %dropflag_hint_11
  store i8 61, i8* %dropflag_hint_14
  store i32 %0, i32* %_argc, align 1
  store i8** %1, i8*** %_argv, align 1
  br label %loop_body

loop_exit:                                        ; No predecessors!
  unreachable

loop_body:                                        ; preds = %loop_body, %entry-block
  %2 = load i8, i8* inttoptr (i16 37 to i8*), align 1
  %3 = or i8 %2, 1
  store i8 %3, i8* inttoptr (i16 37 to i8*), align 1
  br label %loop_body
}

attributes #0 = { uwtable }

Version information

rustc 1.4.0-dev (f841b21fa 2015-09-06)
binary: rustc
commit-hash: f841b21fa4578dc379adad79f1af66b201154b5e
commit-date: 2015-09-06
host: x86_64-apple-darwin
release: 1.4.0-dev

ICE: Layout::compute: unexpected type `[type error]`

I get this while compiling libcore.

error: internal compiler error: /home/dylan/projects/rust-lang/rust/src/librustc/ty/layout.rs:1485: Layout::compute: unexpected type `[type error]`

note: the compiler unexpectedly panicked. this is a bug.

note: we would appreciate a bug report: https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md#bug-reports

thread 'rustc' panicked at 'Box<Any>', /home/dylan/projects/rust-lang/rust/src/librustc_errors/lib.rs:416
note: Run with `RUST_BACKTRACE=1` for a backtrace.

The bug must have been broken somewhere inbetween avr-support-4.0-timnn..master (note that master is at 1db0bbf at the time of writing). Previously, the Rust compiler managed to get all the way to codegen, where LLVM issues would stop us.

Because of this problem, libcore cannot be built.

This may be caused by my fix for #30, but I'm not sure.

cc @shepmaster

LLVM greedy register allocator does not know how to split live variables across register classes

(See below for a further minimized example)

Error message

LLVM ERROR: ran out of registers during register allocation

So from my testing, it seams like the allocator reserves the Z register for the ICALL instruction and then the register class ptrdispregs only has 1 register left and we can't use Y for source and destination.

Reproduction

; ModuleID = 'bugpoint-reduced-simplified.bc'
source_filename = "bugpoint-output-650d16e.bc"
target datalayout = "e-p:16:16:16-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-n8"
target triple = "avr"

%FmtFormatter.5.12.19.26.33.40.54.68.75.82.89.192 = type { i32, [0 x i8], i32, [0 x i8], %"Option<usize>.0.7.14.21.28.35.49.63.70.77.84.187", [0 x i8], %"Option<usize>.0.7.14.21.28.35.49.63.70.77.84.187", [0 x i8], { i8*, void (i8*)** }, [0 x i8], %"Iter<fmt::ArgumentV1>.4.11.18.25.32.39.53.67.74.81.88.191", [0 x i8], { %ArgumentV1.2.9.16.23.30.37.51.65.72.79.86.189*, i16 }, [0 x i8], i8, [3 x i8] }
%"Option<usize>.0.7.14.21.28.35.49.63.70.77.84.187" = type { i16, [0 x i16], [1 x i16] }
%"Iter<fmt::ArgumentV1>.4.11.18.25.32.39.53.67.74.81.88.191" = type { %ArgumentV1.2.9.16.23.30.37.51.65.72.79.86.189*, [0 x i8], %ArgumentV1.2.9.16.23.30.37.51.65.72.79.86.189*, [0 x i8], %"PhantomData<&fmt::ArgumentV1>.3.10.17.24.31.38.52.66.73.80.87.190", [0 x i8] }
%ArgumentV1.2.9.16.23.30.37.51.65.72.79.86.189 = type { %Void.1.8.15.22.29.36.50.64.71.78.85.188*, [0 x i8], i8 (%Void.1.8.15.22.29.36.50.64.71.78.85.188*, %FmtFormatter.5.12.19.26.33.40.54.68.75.82.89.192*)*, [0 x i8] }
%Void.1.8.15.22.29.36.50.64.71.78.85.188 = type { {}, [0 x i8] }
%"PhantomData<&fmt::ArgumentV1>.3.10.17.24.31.38.52.66.73.80.87.190" = type {}
%EscapeUnicode.6.13.20.27.34.41.55.69.76.83.90.193 = type { i32, [0 x i8], i16, [0 x i8], i8, [1 x i8] }

@str.2y = external constant [7 x i8]

; Function Attrs: uwtable
define void @EscapeDefaultStateDebug(%FmtFormatter.5.12.19.26.33.40.54.68.75.82.89.192* dereferenceable(32)) unnamed_addr #0 personality i32 (...)* @rust_eh_personality {
start:
  %_47 = alloca %EscapeUnicode.6.13.20.27.34.41.55.69.76.83.90.193*, align 2
  switch i2 undef, label %bb4 [
    i2 0, label %_ZN4core3fmt8builders10DebugTuple6finish17h8f1e007edfc4d0a6E.exit
  ]

_ZN4core3fmt8builders10DebugTuple6finish17h8f1e007edfc4d0a6E.exit: ; preds = %start
  ret void

bb4:                                              ; preds = %start
  %1 = getelementptr inbounds %FmtFormatter.5.12.19.26.33.40.54.68.75.82.89.192, %FmtFormatter.5.12.19.26.33.40.54.68.75.82.89.192* %0, i16 0, i32 8, i32 1
  %2 = load void (i8*)**, void (i8*)*** %1, align 2, !noalias !0, !nonnull !9
  %3 = getelementptr inbounds void (i8*)*, void (i8*)** %2, i16 3
  %4 = bitcast void (i8*)** %3 to i8 ({}*, i8*, i16)**
  %5 = load i8 ({}*, i8*, i16)*, i8 ({}*, i8*, i16)** %4, align 2, !invariant.load !9, !noalias !0, !nonnull !9
  %6 = tail call i8 %5({}* nonnull undef, i8* noalias nonnull readonly getelementptr inbounds ([7 x i8], [7 x i8]* @str.2y, i16 0, i16 0), i16 7), !noalias !10
  unreachable
}

declare i32 @rust_eh_personality(...) unnamed_addr

attributes #0 = { uwtable }

!0 = !{!1, !3, !5, !6, !8}
!1 = distinct !{!1, !2, !"_ZN4core3fmt9Formatter9write_str17hf8083fd39f1b0c0cE: argument 0"}
!2 = distinct !{!2, !"_ZN4core3fmt9Formatter9write_str17hf8083fd39f1b0c0cE"}
!3 = distinct !{!3, !4, !"_ZN4core3fmt8builders15debug_tuple_new17ha94131b12062f03fE: argument 0"}
!4 = distinct !{!4, !"_ZN4core3fmt8builders15debug_tuple_new17ha94131b12062f03fE"}
!5 = distinct !{!5, !4, !"_ZN4core3fmt8builders15debug_tuple_new17ha94131b12062f03fE: argument 1"}
!6 = distinct !{!6, !7, !"_ZN4core3fmt9Formatter11debug_tuple17hadc8e3bda8cfb00cE: argument 0"}
!7 = distinct !{!7, !"_ZN4core3fmt9Formatter11debug_tuple17hadc8e3bda8cfb00cE"}
!8 = distinct !{!8, !7, !"_ZN4core3fmt9Formatter11debug_tuple17hadc8e3bda8cfb00cE: argument 1"}
!9 = !{}
!10 = !{!3, !6}

I'm not actually sure if Rust or LLVM should be handling this...

Register access is optimised away

Issue #1 forces us to compile with optimisations turned off. Because of this, our outputted assembly is useless because LLVM has mangled all of our well thought out and placed register accessing.

The code

#![feature(lang_items)]
#![feature(macro_rules)]

#![no_std]

const __SFR_OFFSET: uint = 0x20;

/// Defines an AVR IO register.
/// See `avr/sfr_defs.h` in avr-libc.
macro_rules! avr_io_register {
    ($name:ident, $addr:expr) => {
        const $name: *mut u8 = ($addr + __SFR_OFFSET) as *mut u8;
    }
}

/// Defines an AVR register.
/// See `avr/sfr_defs.h` in avr-libc.
macro_rules! avr_mem_register {
    ($name:ident, $addr:expr) => {
        const $name: *mut u8 = $addr as *mut u8;
    }
}

// Port addresses taken from `avr/iom328p.h` in avr-libc.
avr_io_register!(DDRB, 0x04)
avr_io_register!(PORTB, 0x05)

#[start]
fn main(_: int, _: *const *const u8) -> int {

    unsafe {

        // set all port b pins as outputs (I'm too lazy to set this properly).
        *DDRB = 0b11111111;

        loop {

            // set all port b pins to low
            *PORTB = 0b00000000;

            // delay the program somehow.

            // set all port b pins to high
            *PORTB = 0b11111111;

            // delay the program somehow.
        }
    }
    0
}

// required for freestanding Rust.
#[lang="sized"]
trait Sized { }

Is processed by ./rustc ~/Desktop/avr_hello.rs --emit asm -O --target=avr-none and churns out:

    .text
    .file   "avr_hello.0.rs"
    .section    .text.main,"ax",@progbits
    .globl  main
    .align  2
    .type   main,@function
main:
    # load 0xFF into r24
    ldi r24, -1
    # store r24 in IO location 4
    out 4, r24
BB0_1:
    # go back to start, do not pass go, do not collect $200
    rjmp    BB0_1
.Ltmp0:
    .size   main, .Ltmp0-main

Which simply sets DDRB and then executes an empty infinite loop.

This can be fixed by fixing #4 or implementing #6, or alleviated by fixing #1 (so we could at least compile without optimisations).

AVR is Harvard architecture

One problem I've run into (see #47) is that Rust sometimes generates static lookup tables from code, then the generated AVR assembly tries accessing that data using ld. Of course, that doesn't work because AVR uses the Harvard architecture: the program image and RAM are in two completely separate namespaces. There's a separate lpm instruction for loading data from program memory. A similar issue applies to static strings as well.

First off, we need to know when to compile an LLVM IR load instruction into an ld and when to compile it into an lpm. My experimental hack currently selects lpm for isConstant GlobalVariables and ld for everything else.

However, this is problematic because Rust code is free to take pointers to static strings in the form of
str. To support that, we need to do what GCC does, which is to copy over these strings at startup (in a stub pasted to the start of main) to RAM, and then use those addresses with ld.

Putting it all together, my proposal for handling all this would be:

  • Static data emitted by the Rust compiler should never take up RAM. They should always reside in PROGMEM, linked into .text and accessed via lpm.

  • Static data originating from the user (e.g. static strings) should be copied to RAM at startup and that copy should be used (via ld) whenever a pointer is to be taken.

  • Open question: Come up with a nice Rust API for the user to explicitly access PROGMEM when that is what they want (similar to AVR-GCC)

This should be implementable by:

  • On the Rust side, mark lookup tables etc. emitted by Rust with some special attribute (I hope LLVM has support for target-specific attributes) so that the LLVM AVR backend has a way of recognizing them

  • In the LLVM AVR backend, collect all static globals that are not marked with the above special attribute, and generate a stub that copies them into RAM at startup.

  • In the LLVM AVR backend, LowerGlobalAddress checks for that attribute and generates an appropriate wrapper ISD that is then used to dispatch to lpm or ld during instruction selection

Link error in stage1

Hi, I tried to compile your branch avr-support with

./configure --prefix=/opt/local/avrrust && make

which results in a link error (for stage1?):

error: linking with `cc` failed: exit code: 1
note: cc '-m64' '-L' '/Volumes/JKDATA/dev/tmp/avr-rust/x86_64-apple-darwin/stage0/lib/rustlib/x86_64-apple-darwin/lib' '-o' 'x86_64-apple-darwin/stage0/lib/rustlib/x86_64-apple-darwin/lib/librustc-4e7c5e5c.dylib' 'x86_64-apple-darwin/stage0/lib/rustlib/x86_64-apple-darwin/lib/rustc-4e7c5e5c.o' '-Wl,-force_load,/Volumes/JKDATA/dev/tmp/avr-rust/x86_64-apple-darwin/stage0/lib/rustlib/x86_64-apple-darwin/lib/libmorestack.a' 'x86_64-apple-darwin/stage0/lib/rustlib/x86_64-apple-darwin/lib/rustc-4e7c5e5c.metadata.o' '-fno-lto' '-Wl,-dead_strip' '-nodefaultlibs' '-L' '/Volumes/JKDATA/dev/tmp/avr-rust/x86_64-apple-darwin/stage0/lib/rustlib/x86_64-apple-darwin/lib' '-lgraphviz-4e7c5e5c' '-L' '/Volumes/JKDATA/dev/tmp/avr-rust/x86_64-apple-darwin/stage0/lib/rustlib/x86_64-apple-darwin/lib' '-lgetopts-4e7c5e5c' '-L' '/Volumes/JKDATA/dev/tmp/avr-rust/x86_64-apple-darwin/stage0/lib/rustlib/x86_64-apple-darwin/lib' '-lrustc_llvm-4e7c5e5c' '-L' '/Volumes/JKDATA/dev/tmp/avr-rust/x86_64-apple-darwin/stage0/lib/rustlib/x86_64-apple-darwin/lib' '-lrustc_back-4e7c5e5c' '-L' '/Volumes/JKDATA/dev/tmp/avr-rust/x86_64-apple-darwin/stage0/lib/rustlib/x86_64-apple-darwin/lib' '-lsyntax-4e7c5e5c' '-L' '/Volumes/JKDATA/dev/tmp/avr-rust/x86_64-apple-darwin/stage0/lib/rustlib/x86_64-apple-darwin/lib' '-lterm-4e7c5e5c' '-L' '/Volumes/JKDATA/dev/tmp/avr-rust/x86_64-apple-darwin/stage0/lib/rustlib/x86_64-apple-darwin/lib' '-lfmt_macros-4e7c5e5c' '-L' '/Volumes/JKDATA/dev/tmp/avr-rust/x86_64-apple-darwin/stage0/lib/rustlib/x86_64-apple-darwin/lib' '-larena-4e7c5e5c' '-L' '/Volumes/JKDATA/dev/tmp/avr-rust/x86_64-apple-darwin/stage0/lib/rustlib/x86_64-apple-darwin/lib' '-lrbml-4e7c5e5c' '-L' '/Volumes/JKDATA/dev/tmp/avr-rust/x86_64-apple-darwin/stage0/lib/rustlib/x86_64-apple-darwin/lib' '-ltime-4e7c5e5c' '-L' '/Volumes/JKDATA/dev/tmp/avr-rust/x86_64-apple-darwin/stage0/lib/rustlib/x86_64-apple-darwin/lib' '-lserialize-4e7c5e5c' '-L' '/Volumes/JKDATA/dev/tmp/avr-rust/x86_64-apple-darwin/stage0/lib/rustlib/x86_64-apple-darwin/lib' '-llog-4e7c5e5c' '-L' '/Volumes/JKDATA/dev/tmp/avr-rust/x86_64-apple-darwin/stage0/lib/rustlib/x86_64-apple-darwin/lib' '-lregex-4e7c5e5c' '-L' '/Volumes/JKDATA/dev/tmp/avr-rust/x86_64-apple-darwin/stage0/lib/rustlib/x86_64-apple-darwin/lib' '-lflate-4e7c5e5c' '-L' '/Volumes/JKDATA/dev/tmp/avr-rust/x86_64-apple-darwin/stage0/lib/rustlib/x86_64-apple-darwin/lib' '-lstd-4e7c5e5c' '-L' '/Volumes/JKDATA/dev/tmp/avr-rust/x86_64-apple-darwin/stage0/lib/rustlib/x86_64-apple-darwin/lib' '-lsync-4e7c5e5c' '-L' '/Volumes/JKDATA/dev/tmp/avr-rust/x86_64-apple-darwin/stage0/lib/rustlib/x86_64-apple-darwin/lib' '-lrustrt-4e7c5e5c' '-L' 'x86_64-apple-darwin/rt' '-L' '/Volumes/JKDATA/dev/tmp/avr-rust/x86_64-apple-darwin/llvm/Release+Asserts/lib' '-L' '.' '-L' '/Volumes/JKDATA/dev/tmp/avr-rust/.rust' '-L' '/Volumes/JKDATA/dev/tmp/avr-rust' '-lpthread' '-ledit' '-lm' '-lc++' '-lSystem' '-lpthread' '-lc' '-lm' '-dynamiclib' '-Wl,-dylib' '-lcompiler-rt'
note: ld: warning: directory not found for option '-L/Volumes/JKDATA/dev/tmp/avr-rust/.rust'
Undefined symbols for architecture x86_64:
  "_LLVMInitializeAVRTargetInfo", referenced from:
      back::write::configure_llvm::closure.105122 in rustc-4e7c5e5c.o
  "_LLVMInitializeAVRTarget", referenced from:
      back::write::configure_llvm::closure.105122 in rustc-4e7c5e5c.o
  "_LLVMInitializeAVRTargetMC", referenced from:
      back::write::configure_llvm::closure.105122 in rustc-4e7c5e5c.o
  "_LLVMInitializeAVRAsmPrinter", referenced from:
      back::write::configure_llvm::closure.105122 in rustc-4e7c5e5c.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

error: aborting due to previous error
make: *** [x86_64-apple-darwin/stage0/lib/rustlib/x86_64-apple-darwin/lib/stamp.rustc] Error 101

Do I need addtional config flags? thx

Should we include commented-out libcore in avr-rust?

I was wondering what your thoughts were @shepmaster and @gergoerdi on pushing one of the minified versions of libcore you both have so that it is a part of this repo?

There isn't much point in maintaining separate local libcore libraries.

One concern is that it may mean that we get more merge conflicts. We would probably have to comment out parts of libcore in this repository anyway for stuff like float/libcore support.

Other AVR changes to merge into the Rust LLVM fork

This is the list of new commits we have in avr-rust/llvm compared to rust-lang/llvm now:

cbca85fc0e6ec823d483303f19eaaa4617a2e652 [AVR] Fix a bug so that we now emit R_AVR_16 fixups with the correct offset
f2a53d44ce8f2cdb1daa7a61e9e13f4866a5d0b0 [AVR] Implement stacksave/stackrestore by expanding (PR31342)
f2dd609afb61e46fa310feb24b920e701c950007 [AVR] Support zero-sized arguments in defined methods
103e56b3cd49479ab0048a9f5d10c98d48f77ebd [LiveRangeEdit] Don't mess up with LiveInterval when a new vreg is created.
45b94b350229ec89ddf5d8352b4e18d2a2b35f48 [AVR] Do not kill the dest register for a pseudo instruction
243e3dba20f0918adc78e9d5879948dfbf69a310 [AVR] Support the LDWRdPtr instruction with the same Src+Dst register

3 of those correspond to issues filed here; the other 3 "looked interesting" to me so I cherry-picked them - should we actually have those 3? Should they be upstreamed to Rust?

Update to newest Rust

Since I'm playing with this, I figured I'd document some of what I've been seeing.

I've merged rust/rust@1447ce78fbd65a629f228ec8731a5cddc076a15c into the avr-support branch. This entailed a few rounds of merge conflict resolution, as well as updating compiler-rt and the LLVM fork as well. The compiler seems to build, but I've hit some issues with compiling libcore:

./x86_64-apple-darwin/stage1/bin/rustc -C opt-level=2 -Z no-landing-pads --target avr-atmel-none -g ../src/libcore/lib.rs --out-dir libcore-avr/

Specifically, LLVM hit a few assertions when SelectionDAG::computeKnownBits calls APInt::trunc, APInt::sext, and APInt::zext because it's trying to convert a 16-bit number to a 16-bit number. These functions all expect to convert to a different size, and there are methods like zextOrSelf that allow the same size. I hacked around that by returning *this in all three methods (what could go wrong, right?).

The next attempt failed at an LLVM issue:

LLVM ERROR: Cannot select: t35: i8 = mulhs t2, t4
  t2: i8,ch = CopyFromReg t0, Register:i8 %vreg27
    t1: i8 = Register %vreg27
  t4: i8,ch = CopyFromReg t0, Register:i8 %vreg25
    t3: i8 = Register %vreg25
In function: _ZN3num14from_str_radix20h7837196669301488416E

Which I don't have the LLVM understanding to parse yet :-)

I'm going to try some other directions to see if I can get an executable.

Frame pointer clobbered when restoring callee-saved registers

Discovered while working on #38.

I've found a problem which causes Y to be clobbered before function epilogue .

The function emission code looks something like this

  • Emit function prologue
  • Restore callee saved registers
  • Emit function epilogue

It looks like Y is automatically restored before the epilogue is generated. The epilogue assumes that 'Y' still contains SP, but it in actual fact contains its original value at the time the function was called.

This should be an easy fix.

I've been using the same testcase as in #38, shown here

interrupt.ll

; ModuleID = 'interrupt.cgu-0.rs'
source_filename = "interrupt.cgu-0.rs"
target datalayout = "e-p:16:16:16-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-n8"
target triple = "avr-atmel-none"

@__rustc_debug_gdb_scripts_section__ = internal unnamed_addr constant [34 x i8] c"\01gdb_load_rust_pretty_printers.py\00", section ".debug_gdb_scripts", align 1

; Function Attrs: nounwind uwtable
define void @main() unnamed_addr #0 !dbg !5 {
start:
  %tmp_ret2 = alloca i8
  %tmp_ret1 = alloca i8
  %tmp_ret = alloca i8
  %0 = load volatile i8, i8* inttoptr (i16 36 to i8*), align 1, !dbg !10
  store i8 %0, i8* %tmp_ret, !dbg !10
  %1 = load i8, i8* %tmp_ret, !dbg !10
  br label %bb1, !dbg !10

bb1:                                              ; preds = %start
  %2 = or i8 %1, 32, !dbg !10
  store volatile i8 %2, i8* inttoptr (i16 36 to i8*), align 1, !dbg !10
  br label %bb2, !dbg !10

bb2:                                              ; preds = %bb1
  %3 = load volatile i8, i8* inttoptr (i16 129 to i8*), align 1, !dbg !11
  store i8 %3, i8* %tmp_ret1, !dbg !11
  %4 = load i8, i8* %tmp_ret1, !dbg !11
  br label %bb3, !dbg !11

bb3:                                              ; preds = %bb2
  %5 = or i8 %4, 13, !dbg !11
  store volatile i8 %5, i8* inttoptr (i16 129 to i8*), align 1, !dbg !11
  br label %bb4, !dbg !11

bb4:                                              ; preds = %bb3
  store volatile i16 -3036, i16* inttoptr (i16 136 to i16*), align 2, !dbg !12
  br label %bb5, !dbg !12

bb5:                                              ; preds = %bb4
  %6 = load volatile i8, i8* inttoptr (i16 111 to i8*), align 1, !dbg !13
  store i8 %6, i8* %tmp_ret2, !dbg !13
  %7 = load i8, i8* %tmp_ret2, !dbg !13
  br label %bb6, !dbg !13

bb6:                                              ; preds = %bb5
  %8 = or i8 %7, 2, !dbg !13
  store volatile i8 %8, i8* inttoptr (i16 111 to i8*), align 1, !dbg !13
  br label %bb7, !dbg !13

bb7:                                              ; preds = %bb6
  call void asm "SEI", ""(), !dbg !14, !srcloc !15
  br label %bb8, !dbg !16

bb8:                                              ; preds = %bb8, %bb7
  br label %bb8, !dbg !16
}

; Function Attrs: nounwind uwtable
define avr_signalcc  void @__vector_11() unnamed_addr #0 !dbg !17 {
start:
  %tmp_ret = alloca i8
  %0 = load volatile i8, i8* inttoptr (i16 37 to i8*), align 1, !dbg !18
  store i8 %0, i8* %tmp_ret, !dbg !18
  %1 = load i8, i8* %tmp_ret, !dbg !18
  br label %bb1, !dbg !18

bb1:                                              ; preds = %start
  %2 = xor i8 %1, 32, !dbg !18
  store volatile i8 %2, i8* inttoptr (i16 37 to i8*), align 1, !dbg !18
  br label %bb2, !dbg !18

bb2:                                              ; preds = %bb1
  ret void, !dbg !19
}

attributes #0 = { nounwind uwtable "no-frame-pointer-elim"="true" }

!llvm.module.flags = !{!0, !1}
!llvm.dbg.cu = !{!2}

!0 = !{i32 1, !"PIE Level", i32 2}
!1 = !{i32 2, !"Debug Info Version", i32 3}
!2 = distinct !DICompileUnit(language: DW_LANG_Rust, file: !3, producer: "clang LLVM (rustc version 1.18.0-dev (f8982f5c8 2017-04-27))", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4)
!3 = !DIFile(filename: "interrupt", directory: "/home/dylan/projects/builds/rust-lang/avr-rust")
!4 = !{}
!5 = distinct !DISubprogram(name: "main", linkageName: "_ZN9interrupt4mainE", scope: !7, file: !6, line: 87, type: !8, isLocal: false, isDefinition: true, scopeLine: 87, flags: DIFlagPrototyped, isOptimized: false, unit: !2, templateParams: !4, variables: !4)
!6 = !DIFile(filename: "/tmp/interrupt.rs", directory: "/home/dylan/projects/builds/rust-lang/avr-rust")
!7 = !DINamespace(name: "interrupt", scope: null, file: !6, line: 1)
!8 = !DISubroutineType(types: !9)
!9 = !{null}
!10 = !DILocation(line: 89, scope: !5)
!11 = !DILocation(line: 92, scope: !5)
!12 = !DILocation(line: 95, scope: !5)
!13 = !DILocation(line: 98, scope: !5)
!14 = !DILocation(line: 101, scope: !5)
!15 = !{i32 1}
!16 = !DILocation(line: 103, scope: !5)
!17 = distinct !DISubprogram(name: "__vector_11", linkageName: "_ZN9interrupt11__vector_11E", scope: !7, file: !6, line: 108, type: !8, isLocal: false, isDefinition: true, scopeLine: 108, flags: DIFlagPrototyped, isOptimized: false, unit: !2, templateParams: !4, variables: !4)
!18 = !DILocation(line: 109, scope: !17)
!19 = !DILocation(line: 110, scope: !17)

Can't check out sub-repos?

In a fresh checkout out of avr-support@8974f, ollowing the instructions in the README, the configure step fails with this error:

Cloning into '/export/mwm/src/github/avr-rust/rust/src/rust-installer'...
error: no such remote ref 91f0fe0e367edd404ec5576bab070abb92333db9
Fetched in submodule path 'src/compiler-rt', but it did not contain 91f0fe0e367edd404ec5576bab070abb92333db9. Direct fetching of that commit failed.
configure: error: git failed

I'm not sure how that's even possible unless I've got a corrupt repo somewhere. But multiple attempts with completely fresh checkouts of everything are failing.

I have no idea how to proceed from here. Any suggestions for what to do or other information I can provide gladly accepted.

Thanks

Structure passed incorrectly to function

I have the following two functions, where one just calls the other after unpacking a struct:

pub struct S {
    pub op : u8,
    pub x : u8,
    pub addr : u16,
    pub nn : u8,
}

pub enum R {
    A,
    B(u16),
    C(u8),
}

#[inline(never)]
pub fn indirect(raw: S) -> Option<R> {
    direct(raw.op, raw.nn, raw.x, raw.addr)
}

#[inline(never)]
pub fn direct(op: u8, nn: u8, x: u8, addr: u16) -> Option<R> {
    match op {
        0x0 => Some(R::A),
        0x7 => Some(R::B(addr)),
        0xb => Some(R::B(addr)),
        0xf => match nn {
            0x0a => Some(R::C(x)),
            _ => None
        },
        _ => None
    }
}

I am calling it twice, once directly and once via the struct unpacker:

    spi::sync(if direct(0x0f, 0x0a, 0x05, 0x1234).is_some() { 0x42 } else { 0xde });
    spi::sync(if indirect(S{op: 0x0f, nn: 0x0a, x: 0x05, addr: 0x1234}).is_some() { 0x42 } else { 0xde });

However, only the first (direct) one gives the correct result.

Final continuation jump missing from MBB

Here's the minimized LLVM IR:

target triple = "avr-atmel-none"

define internal fastcc void @loopy() unnamed_addr{
start:
  br label %bb7.preheader

bb7.preheader:                                    ; preds = %bb10, %start
  %i = phi i8 [ 0, %start ], [ %j, %bb10 ]
  %j = phi i8 [ 1, %start ], [ %next, %bb10 ]
  br label %bb10

bb4:                                              ; preds = %bb10
  ret void

bb10:                                             ; preds = %bb7.preheader
  tail call fastcc void @observe(i8 %i, i8 1)
  %0 = icmp ult i8 %j, 20
  %1 = zext i1 %0 to i8
  %next = add i8 %j, %1
  br i1 %0, label %bb7.preheader, label %bb4

}

declare void @observe(i8, i8) unnamed_addr;

And here's the generated assembly:

loopy:                                  ; @loopy
; BB#0:                                 ; %start
        push    r16
        push    r17
        ldi     r17, 1
        ldi     r24, 0
LBB0_1:                                 ; %bb4
        pop     r17
        pop     r16
        ret
LBB0_2:                                 ; %bb10
        ldi     r17, 0
LBB0_3:                                 ; %bb10
        add     r17, r16
        cpi     r16, 20
        mov     r24, r16
        brlo    .+2
        rjmp    LBB0_1
; BB#4:                                 ; %bb7.preheader
        mov     r16, r17
        ldi     r17, 1
        ldi     r22, 1
        call    observe
        cpi     r16, 20
        brlo    .+2
        rjmp    LBB0_2
        rjmp    LBB0_3

The problem is that BB#0 doesn't jump to its continuation, and so falls through to LBB0_1 which should only happen at the end of the loop.

Invalid machine code generated for R_AVR_16 fixups

GIven the following main function:

static mut PIXELS: &'static mut [u8] = &mut [0b_1010_0110; 10];

#[no_mangle]
pub extern fn main() {
    unsafe {
        spi::setup();

        for &pixel in PIXELS.iter() {
            spi::sync(pixel);
        }

        loop {}
    }
}

the generated .elf file seems to contain invalid machine code at several places, e.g.

000000b2 <LBB1_5>:
  b2:   8d b5           in      r24, 0x2d       ; 45
  b4:   88 23           and     r24, r24
  b6:   ea f7           brpl    .-6             ; 0xb2 <LBB1_5>
  b8:   8e b5           in      r24, 0x2e       ; 46
  ba:   83 92           .word   0x9283  ; ????
  bc:   00 00           nop
  be:   8e bd           out     0x2e, r24       ; 46

If needed, I can try attaching a full project, but it is basically using a trimmed-down version of libcore. Full .ll listing:

; ModuleID = 'hello_avr.cgu-0.rs'
source_filename = "hello_avr.cgu-0.rs"
target datalayout = "e-p:16:16:16-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-n8"
target triple = "avr-atmel-none"

@ref_mut.0 = internal unnamed_addr global [10 x i8] c"\A6\A6\A6\A6\A6\A6\A6\A6\A6\A6", align 1

; Function Attrs: norecurse nounwind readnone uwtable
define void @rust_eh_personality({}* nocapture, {}* nocapture) unnamed_addr #0 {
start:
  ret void
}


; Function Attrs: noreturn nounwind uwtable
define void @main() unnamed_addr #1 {
start:
  %0 = load volatile i8, i8* inttoptr (i16 37 to i8*), align 1
  %1 = or i8 %0, 4
  store volatile i8 %1, i8* inttoptr (i16 37 to i8*), align 1
  %2 = load volatile i8, i8* inttoptr (i16 36 to i8*), align 4
  %3 = or i8 %2, 44
  store volatile i8 %3, i8* inttoptr (i16 36 to i8*), align 4
  %4 = load volatile i8, i8* inttoptr (i16 36 to i8*), align 4
  %5 = and i8 %4, -17
  store volatile i8 %5, i8* inttoptr (i16 36 to i8*), align 4
  %6 = load volatile i8, i8* inttoptr (i16 76 to i8*), align 4
  %7 = or i8 %6, 80
  store volatile i8 %7, i8* inttoptr (i16 76 to i8*), align 4
  %8 = load i8, i8* getelementptr inbounds ([10 x i8], [10 x i8]* @ref_mut.0, i16 0, i16 0), align 1
  store volatile i8 %8, i8* inttoptr (i16 78 to i8*), align 2
  br label %bb2.i

bb2.i:                                            ; preds = %bb2.i, %start
  %9 = load volatile i8, i8* inttoptr (i16 77 to i8*), align 1
  %10 = icmp sgt i8 %9, -1
  br i1 %10, label %bb2.i, label %_ZN9hello_avr3spi4sync17he0f643349c96805cE.exit

_ZN9hello_avr3spi4sync17he0f643349c96805cE.exit:  ; preds = %bb2.i
  %11 = load volatile i8, i8* inttoptr (i16 78 to i8*), align 2
  %12 = load i8, i8* getelementptr inbounds ([10 x i8], [10 x i8]* @ref_mut.0, i16 0, i16 1), align 1
  store volatile i8 %12, i8* inttoptr (i16 78 to i8*), align 2
  br label %bb2.i.1

bb9:                                              ; preds = %_ZN9hello_avr3spi4sync17he0f643349c96805cE.exit.9, %bb9
  br label %bb9

bb2.i.1:                                          ; preds = %bb2.i.1, %_ZN9hello_avr3spi4sync17he0f643349c96805cE.exit
  %13 = load volatile i8, i8* inttoptr (i16 77 to i8*), align 1
  %14 = icmp sgt i8 %13, -1
  br i1 %14, label %bb2.i.1, label %_ZN9hello_avr3spi4sync17he0f643349c96805cE.exit.1

_ZN9hello_avr3spi4sync17he0f643349c96805cE.exit.1: ; preds = %bb2.i.1
  %15 = load volatile i8, i8* inttoptr (i16 78 to i8*), align 2
  %16 = load i8, i8* getelementptr inbounds ([10 x i8], [10 x i8]* @ref_mut.0, i16 0, i16 2), align 1
  store volatile i8 %16, i8* inttoptr (i16 78 to i8*), align 2
  br label %bb2.i.2

bb2.i.2:                                          ; preds = %bb2.i.2, %_ZN9hello_avr3spi4sync17he0f643349c96805cE.exit.1
  %17 = load volatile i8, i8* inttoptr (i16 77 to i8*), align 1
  %18 = icmp sgt i8 %17, -1
  br i1 %18, label %bb2.i.2, label %_ZN9hello_avr3spi4sync17he0f643349c96805cE.exit.2

_ZN9hello_avr3spi4sync17he0f643349c96805cE.exit.2: ; preds = %bb2.i.2
  %19 = load volatile i8, i8* inttoptr (i16 78 to i8*), align 2
  %20 = load i8, i8* getelementptr inbounds ([10 x i8], [10 x i8]* @ref_mut.0, i16 0, i16 3), align 1
  store volatile i8 %20, i8* inttoptr (i16 78 to i8*), align 2
  br label %bb2.i.3

bb2.i.3:                                          ; preds = %bb2.i.3, %_ZN9hello_avr3spi4sync17he0f643349c96805cE.exit.2
  %21 = load volatile i8, i8* inttoptr (i16 77 to i8*), align 1
  %22 = icmp sgt i8 %21, -1
  br i1 %22, label %bb2.i.3, label %_ZN9hello_avr3spi4sync17he0f643349c96805cE.exit.3

_ZN9hello_avr3spi4sync17he0f643349c96805cE.exit.3: ; preds = %bb2.i.3
  %23 = load volatile i8, i8* inttoptr (i16 78 to i8*), align 2
  %24 = load i8, i8* getelementptr inbounds ([10 x i8], [10 x i8]* @ref_mut.0, i16 0, i16 4), align 1
  store volatile i8 %24, i8* inttoptr (i16 78 to i8*), align 2
  br label %bb2.i.4

bb2.i.4:                                          ; preds = %bb2.i.4, %_ZN9hello_avr3spi4sync17he0f643349c96805cE.exit.3
  %25 = load volatile i8, i8* inttoptr (i16 77 to i8*), align 1
  %26 = icmp sgt i8 %25, -1
  br i1 %26, label %bb2.i.4, label %_ZN9hello_avr3spi4sync17he0f643349c96805cE.exit.4

_ZN9hello_avr3spi4sync17he0f643349c96805cE.exit.4: ; preds = %bb2.i.4
  %27 = load volatile i8, i8* inttoptr (i16 78 to i8*), align 2
  %28 = load i8, i8* getelementptr inbounds ([10 x i8], [10 x i8]* @ref_mut.0, i16 0, i16 5), align 1
  store volatile i8 %28, i8* inttoptr (i16 78 to i8*), align 2
  br label %bb2.i.5

bb2.i.5:                                          ; preds = %bb2.i.5, %_ZN9hello_avr3spi4sync17he0f643349c96805cE.exit.4
  %29 = load volatile i8, i8* inttoptr (i16 77 to i8*), align 1
  %30 = icmp sgt i8 %29, -1
  br i1 %30, label %bb2.i.5, label %_ZN9hello_avr3spi4sync17he0f643349c96805cE.exit.5

_ZN9hello_avr3spi4sync17he0f643349c96805cE.exit.5: ; preds = %bb2.i.5
  %31 = load volatile i8, i8* inttoptr (i16 78 to i8*), align 2
  %32 = load i8, i8* getelementptr inbounds ([10 x i8], [10 x i8]* @ref_mut.0, i16 0, i16 6), align 1
  store volatile i8 %32, i8* inttoptr (i16 78 to i8*), align 2
  br label %bb2.i.6

bb2.i.6:                                          ; preds = %bb2.i.6, %_ZN9hello_avr3spi4sync17he0f643349c96805cE.exit.5
  %33 = load volatile i8, i8* inttoptr (i16 77 to i8*), align 1
  %34 = icmp sgt i8 %33, -1
  br i1 %34, label %bb2.i.6, label %_ZN9hello_avr3spi4sync17he0f643349c96805cE.exit.6

_ZN9hello_avr3spi4sync17he0f643349c96805cE.exit.6: ; preds = %bb2.i.6
  %35 = load volatile i8, i8* inttoptr (i16 78 to i8*), align 2
  %36 = load i8, i8* getelementptr inbounds ([10 x i8], [10 x i8]* @ref_mut.0, i16 0, i16 7), align 1
  store volatile i8 %36, i8* inttoptr (i16 78 to i8*), align 2
  br label %bb2.i.7

bb2.i.7:                                          ; preds = %bb2.i.7, %_ZN9hello_avr3spi4sync17he0f643349c96805cE.exit.6
  %37 = load volatile i8, i8* inttoptr (i16 77 to i8*), align 1
  %38 = icmp sgt i8 %37, -1
  br i1 %38, label %bb2.i.7, label %_ZN9hello_avr3spi4sync17he0f643349c96805cE.exit.7

_ZN9hello_avr3spi4sync17he0f643349c96805cE.exit.7: ; preds = %bb2.i.7
  %39 = load volatile i8, i8* inttoptr (i16 78 to i8*), align 2
  %40 = load i8, i8* getelementptr inbounds ([10 x i8], [10 x i8]* @ref_mut.0, i16 0, i16 8), align 1
  store volatile i8 %40, i8* inttoptr (i16 78 to i8*), align 2
  br label %bb2.i.8

bb2.i.8:                                          ; preds = %bb2.i.8, %_ZN9hello_avr3spi4sync17he0f643349c96805cE.exit.7
  %41 = load volatile i8, i8* inttoptr (i16 77 to i8*), align 1
  %42 = icmp sgt i8 %41, -1
  br i1 %42, label %bb2.i.8, label %_ZN9hello_avr3spi4sync17he0f643349c96805cE.exit.8

_ZN9hello_avr3spi4sync17he0f643349c96805cE.exit.8: ; preds = %bb2.i.8
  %43 = load volatile i8, i8* inttoptr (i16 78 to i8*), align 2
  %44 = load i8, i8* getelementptr inbounds ([10 x i8], [10 x i8]* @ref_mut.0, i16 0, i16 9), align 1
  store volatile i8 %44, i8* inttoptr (i16 78 to i8*), align 2
  br label %bb2.i.9

bb2.i.9:                                          ; preds = %bb2.i.9, %_ZN9hello_avr3spi4sync17he0f643349c96805cE.exit.8
  %45 = load volatile i8, i8* inttoptr (i16 77 to i8*), align 1
  %46 = icmp sgt i8 %45, -1
  br i1 %46, label %bb2.i.9, label %_ZN9hello_avr3spi4sync17he0f643349c96805cE.exit.9

_ZN9hello_avr3spi4sync17he0f643349c96805cE.exit.9: ; preds = %bb2.i.9
  %47 = load volatile i8, i8* inttoptr (i16 78 to i8*), align 2
  br label %bb9
}

attributes #0 = { norecurse nounwind readnone uwtable }
attributes #1 = { noreturn nounwind uwtable }

!llvm.module.flags = !{!0}

!0 = !{i32 1, !"PIE Level", i32 2}

Switch lookup gets turned into a branch to a wrong address

I have the following Rust code:

#[inline(never)]
pub fn decode(n: u8) -> bool {
    match n {
        0x0 => Some(()),
        0x1 => Some(()),
        0x2 => Some(()),
        0x3 => Some(()),
        0x6 => Some(()),
        _ => None
    }.is_some()
}

It is turned into the following LLVM IR:

; ModuleID = 'external.cgu-0.rs'
source_filename = "external.cgu-0.rs"
target datalayout = "e-p:16:16:16-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-n8"
target triple = "avr-atmel-none"

; Function Attrs: noinline nounwind readnone uwtable
define zeroext i1 @_ZN8external6decode17hac8ff9e06698feb0E(i8) unnamed_addr #0 {
start:
  %1 = icmp ult i8 %0, 7
  br i1 %1, label %switch.lookup, label %bb7

switch.lookup:                                    ; preds = %start
  %2 = sext i8 %0 to i16
  %3 = and i16 %2, -2
  %.cmp = icmp ne i16 %3, 4
  br label %bb7

bb7:                                              ; preds = %start, %switch.lookup
  %.sink = phi i1 [ %.cmp, %switch.lookup ], [ false, %start ]
  ret i1 %.sink
}

attributes #0 = { noinline nounwind readnone uwtable }

Compiling that LLVM IR, the resulting object file is, I believe, wrong.

$ avr-objdump -dr external-4c5561d448dd0019.o 

external-4c5561d448dd0019.o:     file format elf32-avr


Disassembly of section .text:

00000000 <_ZN8external6decode17hac8ff9e06698feb0E>:
   0:	87 30       	cpi	r24, 0x07	; 7
   2:	90 e0       	ldi	r25, 0x00	; 0
   4:	00 f4       	brcc	.+0      	; 0x6 <_ZN8external6decode17hac8ff9e06698feb0E+0x6>
			4: R_AVR_7_PCREL	.text+0x1e
   6:	28 2f       	mov	r18, r24
   8:	38 2f       	mov	r19, r24
   a:	33 0f       	add	r19, r19
   c:	33 0b       	sbc	r19, r19
   e:	2e 7f       	andi	r18, 0xFE	; 254
  10:	44 e0       	ldi	r20, 0x04	; 4
  12:	50 e0       	ldi	r21, 0x00	; 0
  14:	91 e0       	ldi	r25, 0x01	; 1
  16:	24 17       	cp	r18, r20
  18:	35 07       	cpc	r19, r21
  1a:	01 f4       	brne	.+0      	; 0x1c <_ZN8external6decode17hac8ff9e06698feb0E+0x1c>
			1a: R_AVR_7_PCREL	.text+0x26
  1c:	90 e0       	ldi	r25, 0x00	; 0

0000001e <LBB0_4>:
  1e:	91 70       	andi	r25, 0x01	; 1
  20:	89 2f       	mov	r24, r25
  22:	99 27       	eor	r25, r25
  24:	08 95       	ret

Note that the relocation for 0x1a targets 0x26, which is after the end of the function. I believe the correct target would be 0x1e.

Implement morestack and record_sp

Currently the runtime functions __morestack and record_sp are filled with stubs which simply perform an infinite loop.

The assembly files can be found in src/rt/arch/avr.

This bug will cause some programs to halt without warning in specific circumstances.

Configure Clang Version

The Clang version in Configure fails for the latest version of Clang.

if [ -n "$CFG_OSX_CLANG_VERSION" ] then case $CFG_OSX_CLANG_VERSION in (7.0*)

Should read:

if [ -n "$CFG_OSX_CLANG_VERSION" ] then case $CFG_OSX_CLANG_VERSION in (7.*)

Rebase onto rust master?

So, llvm-avr was merged into llvm proper. This means this project can probably be less experimental in nature. What changes were actually made to make it work? and would it be difficult to rebase these changes on the current rust master branch?

CPI, and who knows what other instructions, are defined with wrong operand registers

LLVM IR:

target triple = "avr-atmel-none"

define internal fastcc void @loopy() unnamed_addr {
start:
  br label %bb7.preheader

bb2.loopexit:                                     ; preds = %bb10
  %0 = icmp ult i8 %.iter.sroa.0.020, 20
  %1 = zext i1 %0 to i8
  %.iter.sroa.0.0 = add i8 %.iter.sroa.0.020, %1
  br i1 %0, label %bb7.preheader, label %bb4

bb7.preheader:                                    ; preds = %bb2.loopexit, %start
  %iter.sroa.0.0.21 = phi i8 [ 0, %start ], [ %.iter.sroa.0.020, %bb2.loopexit ]
  %.iter.sroa.0.020 = phi i8 [ 1, %start ], [ %.iter.sroa.0.0, %bb2.loopexit ]
  %2 = add i8 %iter.sroa.0.0.21, 10
  br label %bb10

bb4:                                              ; preds = %bb2.loopexit
  ret void

bb10:                                             ; preds = %bb10, %bb7.preheader
  %iter1.sroa.0.0.19 = phi i8 [ 0, %bb7.preheader ], [ %.iter1.sroa.0.018, %bb10 ]
  %.iter1.sroa.0.018 = phi i8 [ 1, %bb7.preheader ], [ %.iter1.sroa.0.0, %bb10 ]
  tail call fastcc void @observe(i8 %2, i8 %iter1.sroa.0.0.19)
  %3 = icmp ult i8 %.iter1.sroa.0.018, 48
  %4 = zext i1 %3 to i8
  %.iter1.sroa.0.0 = add i8 %.iter1.sroa.0.018, %4
  br i1 %3, label %bb10, label %bb2.loopexit
}

declare void @observe(i8, i8) unnamed_addr #2

Generated assembly with --filetype=asm:

	.text
	.file	"a.ll"
	.p2align	1
	.type	loopy,@function
loopy:                                  ; @loopy
; BB#0:                                 ; %start
	push	r15
	push	r16
	push	r17
	ldi	r24, 1
	ldi	r17, 0
LBB0_3:                                 ; %bb7.preheader
                                        ; =>This Loop Header: Depth=1
                                        ;     Child Loop BB0_4 Depth 2
	mov	r15, r24
	subi	r17, -10
	ldi	r16, 1
	ldi	r22, 0
LBB0_4:                                 ; %bb10
                                        ;   Parent Loop BB0_3 Depth=1
                                        ; =>  This Inner Loop Header: Depth=2
	mov	r24, r17
	call	observe
	cpi	r16, 48
	ldi	r24, 1
	brsh	.+2
	rjmp	LBB0_5
; BB#6:                                 ; %bb10
                                        ;   in Loop: Header=BB0_4 Depth=2
	ldi	r24, 0
LBB0_5:                                 ; %bb10
                                        ;   in Loop: Header=BB0_4 Depth=2
	add	r24, r16
	cpi	r16, 48
	mov	r22, r16
	mov	r16, r24
	brsh	.+2
	rjmp	LBB0_4
; BB#1:                                 ; %bb2.loopexit
                                        ;   in Loop: Header=BB0_3 Depth=1
	ldi	r24, 1
	cpi	r15, 20
	brsh	.+2
	rjmp	LBB0_2
; BB#7:                                 ; %bb2.loopexit
                                        ;   in Loop: Header=BB0_3 Depth=1
	ldi	r24, 0
LBB0_2:                                 ; %bb2.loopexit
                                        ;   in Loop: Header=BB0_3 Depth=1
	add	r24, r15
	cpi	r15, 20
	mov	r17, r15
	brsh	.+2
	rjmp	LBB0_3
; BB#8:                                 ; %bb4
	pop	r17
	pop	r16
	pop	r15
	ret
.Lfunc_end0:
	.size	loopy, .Lfunc_end0-loopy

Disassembly of output generated with --filetype=obj:


a.o:     file format elf32-avr


Disassembly of section .text:

00000000 <loopy>:
   0:	ff 92       	push	r15
   2:	0f 93       	push	r16
   4:	1f 93       	push	r17
   6:	81 e0       	ldi	r24, 0x01	; 1
   8:	10 e0       	ldi	r17, 0x00	; 0

0000000a <LBB0_3>:
   a:	f8 2e       	mov	r15, r24
   c:	16 5f       	subi	r17, 0xF6	; 246
   e:	01 e0       	ldi	r16, 0x01	; 1
  10:	60 e0       	ldi	r22, 0x00	; 0

00000012 <LBB0_4>:
  12:	81 2f       	mov	r24, r17
  14:	0e 94 00 00 	call	0	; 0x0 <loopy>
  18:	00 33       	cpi	r16, 0x30	; 48
  1a:	81 e0       	ldi	r24, 0x01	; 1
  1c:	08 f4       	brcc	.+2      	; 0x20 <LBB0_4+0xe>
  1e:	00 c0       	rjmp	.+0      	; 0x20 <LBB0_4+0xe>
  20:	80 e0       	ldi	r24, 0x00	; 0

00000022 <LBB0_5>:
  22:	80 0f       	add	r24, r16
  24:	00 33       	cpi	r16, 0x30	; 48
  26:	60 2f       	mov	r22, r16
  28:	08 2f       	mov	r16, r24
  2a:	08 f4       	brcc	.+2      	; 0x2e <LBB0_5+0xc>
  2c:	00 c0       	rjmp	.+0      	; 0x2e <LBB0_5+0xc>
  2e:	81 e0       	ldi	r24, 0x01	; 1
  30:	f4 31       	cpi	r31, 0x14	; 20
  32:	08 f4       	brcc	.+2      	; 0x36 <LBB0_5+0x14>
  34:	00 c0       	rjmp	.+0      	; 0x36 <LBB0_5+0x14>
  36:	80 e0       	ldi	r24, 0x00	; 0

00000038 <LBB0_2>:
  38:	8f 0d       	add	r24, r15
  3a:	f4 31       	cpi	r31, 0x14	; 20
  3c:	1f 2d       	mov	r17, r15
  3e:	08 f4       	brcc	.+2      	; 0x42 <LBB0_2+0xa>
  40:	00 c0       	rjmp	.+0      	; 0x42 <LBB0_2+0xa>
  42:	1f 91       	pop	r17
  44:	0f 91       	pop	r16
  46:	ff 90       	pop	r15
  48:	08 95       	ret

Note that the .o file uses r31 for comparisons (without ever filling that register) while the .s file, correctly, uses r15, e.g. in LBB0_2:

LBB0_2:                                 ; %bb2.loopexit
                                        ;   in Loop: Header=BB0_3 Depth=1
	add	r24, r15
	cpi	r15, 20
00000038 <LBB0_2>:
  38:	8f 0d       	add	r24, r15
  3a:	f4 31       	cpi	r31, 0x14	; 20

Frame pointer clobbered in some functions which have spills

I'm trying to add an interrupt handler to TIMER1_COMPA to flash PB5. Here's what I tried:

#[no_mangle]
pub unsafe extern "avr-interrupt" fn __vector_11() {
    volatile_store(PORTB, volatile_load(PORTB) ^ MASK);
}

simavr reports that the generated executable goes wrong after running the handler twice:

CORE: *** Invalid read address PC=0136 SP=2022 O=901f Address 2023 out of ram (08ff)
avr_sadly_crashed

Standalone, full test case:

#![feature(no_core)]
#![feature(lang_items)]
#![feature(fundamental)]
#![feature(intrinsics)]
#![feature(optin_builtin_traits)]
#![feature(asm)]
#![feature(abi_avr_interrupt)]

#![no_core]
#![no_main]

mod clone {
    use marker::Sized;

    pub trait Clone : Sized {
        fn clone(&self) -> Self;

        #[inline(always)]
        fn clone_from(&mut self, source: &Self) {
            *self = source.clone()
        }
    }
}

mod marker {
    use clone::Clone;

    #[lang = "sized"]
    #[fundamental]
    pub trait Sized {}

    #[lang = "copy"]
    pub trait Copy : Clone {}


    #[lang = "freeze"]
    unsafe trait Freeze {}

    unsafe impl Freeze for .. {}
}

mod ops {
    #[lang = "bitor"]
    pub trait BitOr {
        fn bitor(self, rhs: Self) -> Self;
    }

    impl BitOr for u8 {
        #[inline]
        fn bitor(self, rhs: u8) -> u8 { self | rhs }
    }


    #[lang = "bitxor"]
    pub trait BitXor {
        fn bitxor(self, rhs: Self) -> Self;
    }

    impl BitXor for u8 {
        #[inline]
        fn bitxor(self, other: u8) -> u8 { self ^ other }
    }
}

mod intrinsics {
    extern "rust-intrinsic" {
        pub fn volatile_load<T>(src: *const T) -> T;
        pub fn volatile_store<T>(dst: *mut T, val: T);
    }
}

use intrinsics::{volatile_load, volatile_store};

mod avr {
    pub const DDRB:   *mut u8  = 0x24 as *mut u8;
    pub const PORTB:  *mut u8  = 0x25 as *mut u8;
    pub const TCCR1B: *mut u8  = 0x81 as *mut u8;
    pub const TIMSK1: *mut u8  = 0x6f as *mut u8;
    pub const OCR1A:  *mut u16 = 0x88 as *mut u16;
}

use avr::*;

const MASK: u8 = 0b_0010_0000;

#[no_mangle]
pub extern fn main() {
    unsafe {
        volatile_store(DDRB, volatile_load(DDRB) | MASK);

        // Configure timer 1 for CTC mode, with divider of 64
        volatile_store(TCCR1B, volatile_load(TCCR1B) | 0b_0000_1101);

        // Timer frequency
        volatile_store(OCR1A, 62500);

        // Enable CTC interrupt
        volatile_store(TIMSK1, volatile_load(TIMSK1) | 0b_0000_0010);

        // Good to go!
        asm!("SEI");

        loop {}
    }
}

#[no_mangle]
pub unsafe extern "avr-interrupt" fn __vector_11() {
    volatile_store(PORTB, volatile_load(PORTB) ^ MASK);
}

Assertion "LowerFormalArguments didn't emit the correct number of values!" failed

target triple = "avr-atmel-none"

; Function Attrs: norecurse nounwind readonly uwtable
define i128 @"_ZN43_$LT$i32$u20$as$u20$core..fmt..num..Int$GT$7to_u12817haa6ed143bf6636caE"(i32* noalias nocapture readonly dereferenceable(4)) unnamed_addr #6 {
start:
  %1 = load i32, i32* %0, align 4
  %2 = sext i32 %1 to i128
  ret i128 %2
}

EDIT (@dylanmckay): Here is another reproduction caused with non-i128 types. This was originally raised on #89. We should double check whatever fix is made fixes both of these.

declare i8 @do_something(i8 %val)

define { i1, i8 } @main(i8) #2 {
entry:
  %1 = call zeroext i8 @do_something(i8 zeroext %0)
  %2 = insertvalue { i1, i8 } { i1 true, i8 undef }, i8 %1, 1
  ret { i1, i8 } %2
}
CodeGen/SelectionDAG/SelectionDAGBuilder.cpp:8143: void llvm::SelectionDAGISel::LowerArguments(const llvm::Function&): Assertion `InVals.size() == Ins.size() && "LowerFormalArguments didn't emit the correct number of values!"' failed.
#0 0x0000000001721085 llvm::sys::PrintStackTrace(llvm::raw_ostream&) (/home/cactus/prog/rust/rust-avr/build/build/x86_64-unknown-linux-gnu/llvm/bin/llc+0x1721085)
#1 0x000000000171f09e llvm::sys::RunSignalHandlers() (/home/cactus/prog/rust/rust-avr/build/build/x86_64-unknown-linux-gnu/llvm/bin/llc+0x171f09e)
#2 0x000000000171f202 SignalHandler(int) (/home/cactus/prog/rust/rust-avr/build/build/x86_64-unknown-linux-gnu/llvm/bin/llc+0x171f202)
#3 0x00007fa62aaf3330 __restore_rt (/lib/x86_64-linux-gnu/libpthread.so.0+0x10330)
#4 0x00007fa629cafc37 gsignal (/lib/x86_64-linux-gnu/libc.so.6+0x36c37)
#5 0x00007fa629cb3028 abort (/lib/x86_64-linux-gnu/libc.so.6+0x3a028)
#6 0x00007fa629ca8bf6 (/lib/x86_64-linux-gnu/libc.so.6+0x2fbf6)
#7 0x00007fa629ca8ca2 (/lib/x86_64-linux-gnu/libc.so.6+0x2fca2)
#8 0x00000000015c0f83 llvm::SelectionDAGISel::LowerArguments(llvm::Function const&) (/home/cactus/prog/rust/rust-avr/build/build/x86_64-unknown-linux-gnu/llvm/bin/llc+0x15c0f83)
#9 0x00000000016091cc llvm::SelectionDAGISel::SelectAllBasicBlocks(llvm::Function const&) (/home/cactus/prog/rust/rust-avr/build/build/x86_64-unknown-linux-gnu/llvm/bin/llc+0x16091cc)
#10 0x000000000160ac3c llvm::SelectionDAGISel::runOnMachineFunction(llvm::MachineFunction&) [clone .part.948] (/home/cactus/prog/rust/rust-avr/build/build/x86_64-unknown-linux-gnu/llvm/bin/llc+0x160ac3c)
#11 0x00000000010e8523 llvm::MachineFunctionPass::runOnFunction(llvm::Function&) (/home/cactus/prog/rust/rust-avr/build/build/x86_64-unknown-linux-gnu/llvm/bin/llc+0x10e8523)
#12 0x000000000138ba03 llvm::FPPassManager::runOnFunction(llvm::Function&) (/home/cactus/prog/rust/rust-avr/build/build/x86_64-unknown-linux-gnu/llvm/bin/llc+0x138ba03)
#13 0x000000000138baac llvm::FPPassManager::runOnModule(llvm::Module&) (/home/cactus/prog/rust/rust-avr/build/build/x86_64-unknown-linux-gnu/llvm/bin/llc+0x138baac)
#14 0x000000000138c80f llvm::legacy::PassManagerImpl::run(llvm::Module&) (/home/cactus/prog/rust/rust-avr/build/build/x86_64-unknown-linux-gnu/llvm/bin/llc+0x138c80f)
#15 0x0000000000697f74 compileModule(char**, llvm::LLVMContext&) (/home/cactus/prog/rust/rust-avr/build/build/x86_64-unknown-linux-gnu/llvm/bin/llc+0x697f74)
#16 0x0000000000646a90 main (/home/cactus/prog/rust/rust-avr/build/build/x86_64-unknown-linux-gnu/llvm/bin/llc+0x646a90)
#17 0x00007fa629c9af45 __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21f45)
#18 0x000000000068d2b5 _start (/home/cactus/prog/rust/rust-avr/build/build/x86_64-unknown-linux-gnu/llvm/bin/llc+0x68d2b5)
Stack dump:
0.	Program arguments: /home/cactus/prog/rust/rust-avr/build/build/x86_64-unknown-linux-gnu/llvm/bin/llc -mcpu=atmega328p a.ll 
1.	Running pass 'Function Pass Manager' on module 'a.ll'.
2.	Running pass 'AVR DAG->DAG Instruction Selection' on function '@"_ZN43_$LT$i32$u20$as$u20$core..fmt..num..Int$GT$7to_u12817haa6ed143bf6636caE"'

Support AVR as the default target

Set the default target to avr-unknown-unknown so that by default we attempt to build for AVR.

Currently this is blocked by not being able to compile compiler-rt and libcore and such.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.