Some of the things that needed to be implemented in the frontend was the ABI, unwind support, C bindings for the new architecture. Some of these don't apply as much to rust but you can see that LLVM doesn't do a perfect job. The diff is still quite small however.
Additionally, it is useful for the front-end to understand things like the layout of types, and the standard library usually also needs changes to paper over any platform differences (although I imagine AVR doesn't need many, mostly in the compiler-support library compiler-rt, given not much of the standard library will work).
> Rust's version of LLVM has a few patches on top of stock LLVM, and it also tended to have extra commits cherry-picked on top.
Apart from that, Rust needs very little per-architecture glue code. And someone needs to run the Rust testsuite on the resulting version of Rust and make sure it passes.
In the AVR case, on the biggest chips a RAM address takes 2 bytes while a flash address is 3 bytes, and on the smallest a RAM address is 1 byte while a flash address is 2, and of course the values overlap (flash-address-0xFE points to different memory than RAM-address-0xFE), and the indirection code is different. So how big is a plain 'char *', and how do you dereference it? On a small AVR you don't want to be wasting precious memory storing and copying 2 bytes when 1 will do, and you sure don't want a run-time test on every dereference — if you had the cost/time/battery for that you wouldn't have picked² a small AVR in the first place. So you need to be able to tell the compiler what kind of memory a pointer points to.
The big free toolchains (gcc/llvm) don't pay much attention to non-mainstream processors, which is why a handful of commercial compilers still exist.
I suppose (not being a Rust expert) that a Rust compiler could figure out that a non-mut 'static can go in flash, and track address spaces, and auto-genericize functions that take a reference… but I'll bet it doesn't, yet.
¹ http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1169.pdf
² no pun intended originally, but I'm leaving it and gratuitously calling attention to it.
(My mental model was that once you add a backend to Llvm, every programming language that uses llvm should magically work with it.) Does LLVM's design fail to capture the full problem space? Are there out of band concerns that do not lend themselves to be generally expressed?