| ; RUN: llc < %s -march=avr -mcpu=atmega328p | FileCheck %s | |
| ; This test checks a basic 'blinking led' program. | |
| ; It is written for the ATmega328P | |
| ; Derived from the following C program (with some cleanups): | |
| ; #include <avr/io.h> | |
| ; | |
| ; void setup_ddr() { | |
| ; DDRB |= _BV(PB5); | |
| ; } | |
| ; | |
| ; void turn_on() { | |
| ; PORTB |= _BV(PB5); | |
| ; } | |
| ; | |
| ; void turn_off() { | |
| ; PORTB &= ~_BV(PB5); | |
| ; } | |
| ; | |
| ; int main() { | |
| ; setup_ddr(); | |
| ; | |
| ; while(1) { | |
| ; turn_on(); | |
| ; turn_off(); | |
| ; } | |
| ; | |
| ; return 0; | |
| ; } | |
| ; Sets up the data direction register. | |
| ; CHECK-LABEL: setup_ddr | |
| define void @setup_ddr() { | |
| entry: | |
| ; This should load the value of DDRB, OR it with the bit number and store | |
| ; the result back to DDRB. | |
| ; CHECK: in [[TMPREG:r[0-9]+]], 4 | |
| ; CHECK-NEXT: ori [[TMPREG]], 32 | |
| ; CHECK-NOT: ori {{r[0-9]+}}, 0 | |
| ; CHECK-NEXT: out 4, [[TMPREG]] | |
| ; CHECK-NEXT: ret | |
| %0 = load volatile i8, i8* inttoptr (i16 36 to i8*), align 1 | |
| %conv = zext i8 %0 to i16 | |
| %or = or i16 %conv, 32 | |
| %conv1 = trunc i16 %or to i8 | |
| store volatile i8 %conv1, i8* inttoptr (i16 36 to i8*), align 1 | |
| ret void | |
| } | |
| ; Turns on the LED. | |
| ; CHECK-LABEL: turn_on | |
| define void @turn_on() { | |
| entry: | |
| ; This should load the value of PORTB, OR it with the bit number and store | |
| ; the result back to DDRB. | |
| ; CHECK: in [[TMPREG:r[0-9]+]], 5 | |
| ; CHECK-NEXT: ori [[TMPREG]], 32 | |
| ; CHECK-NOT: ori {{r[0-9]+}}, 0 | |
| ; CHECK-NEXT: out 5, [[TMPREG]] | |
| ; CHECK-NEXT: ret | |
| %0 = load volatile i8, i8* inttoptr (i16 37 to i8*), align 1 | |
| %conv = zext i8 %0 to i16 | |
| %or = or i16 %conv, 32 | |
| %conv1 = trunc i16 %or to i8 | |
| store volatile i8 %conv1, i8* inttoptr (i16 37 to i8*), align 1 | |
| ret void | |
| } | |
| ; Turns off the LED. | |
| ; CHECK-LABEL: turn_off | |
| define void @turn_off() { | |
| entry: | |
| ; This should load the value of PORTB, OR it with the bit number and store | |
| ; the result back to DDRB. | |
| ; CHECK: in [[TMPREG:r[0-9]+]], 5 | |
| ; CHECK-NEXT: andi [[TMPREG]], 223 | |
| ; CHECK-NEXT: andi {{r[0-9]+}}, 0 | |
| ; CHECK-NEXT: out 5, [[TMPREG]] | |
| ; CHECK-NEXT: ret | |
| %0 = load volatile i8, i8* inttoptr (i16 37 to i8*), align 1 | |
| %conv = zext i8 %0 to i16 | |
| %and = and i16 %conv, -33 | |
| %conv1 = trunc i16 %and to i8 | |
| store volatile i8 %conv1, i8* inttoptr (i16 37 to i8*), align 1 | |
| ret void | |
| } | |
| ; CHECK-LABEL: main | |
| define i16 @main() { | |
| entry: | |
| ; CHECK: call setup_ddr | |
| call void @setup_ddr() | |
| br label %while.body | |
| ; CHECK-LABEL: LBB3_1 | |
| while.body: | |
| ; CHECK: call turn_on | |
| call void @turn_on() | |
| ; CHECK-NEXT: call turn_off | |
| call void @turn_off() | |
| ; CHECK-NEXT: rjmp LBB3_1 | |
| br label %while.body | |
| } |