| ; RUN: llc -mtriple=avr -mcpu=atmega328 -O1 -verify-machineinstrs < %s | FileCheck %s |
| |
| declare void @use(ptr %x); |
| |
| ; Case: One 2-byte variable with alignment of 1. |
| ; |
| ; This shouldn't activate stack realignment - this function exists so that it's |
| ; easy to see the difference when stack realignment gets actually activated (see |
| ; the next test case). |
| define i16 @no_alignment() { |
| ; CHECK-LABEL: no_alignment: |
| ; CHECK-NEXT: ; %bb.0: |
| ; |
| ;; prologue |
| ; CHECK-NEXT: push r28 |
| ; CHECK-NEXT: push r29 |
| ; CHECK-NEXT: in r28, 61 |
| ; CHECK-NEXT: in r29, 62 |
| ; CHECK-NEXT: sbiw r28, 2 |
| ; CHECK-NEXT: in r0, 63 |
| ; CHECK-NEXT: cli |
| ; CHECK-NEXT: out 62, r29 |
| ; CHECK-NEXT: out 63, r0 |
| ; CHECK-NEXT: out 61, r28 |
| ; |
| ;; call void @use(ptr %1) |
| ; CHECK-NEXT: movw r24, r28 |
| ; CHECK-NEXT: adiw r24, 1 |
| ; CHECK-NEXT: call use |
| ; |
| ;; %2 = load i16, ptr %1, align 1 |
| ; CHECK-NEXT: ldd r24, Y+1 |
| ; CHECK-NEXT: ldd r25, Y+2 |
| ; |
| ;; epilogue |
| ; CHECK-NEXT: adiw r28, 2 |
| ; CHECK-NEXT: in r0, 63 |
| ; CHECK-NEXT: cli |
| ; CHECK-NEXT: out 62, r29 |
| ; CHECK-NEXT: out 63, r0 |
| ; CHECK-NEXT: out 61, r28 |
| ; CHECK-NEXT: pop r29 |
| ; CHECK-NEXT: pop r28 |
| ; CHECK-NEXT: ret |
| |
| %1 = alloca i16, align 1 |
| call void @use(ptr %1) |
| %2 = load i16, ptr %1, align 1 |
| |
| ret i16 %2 |
| } |
| |
| ; Case: One 2-byte variable with alignment of 16. |
| ; |
| ; This reserves 2 + 16 - 1 = 17 bytes of stack space and allocates an extra |
| ; aligned stack pointer (in this case into r24:r25). |
| define i16 @some_alignment() { |
| ; CHECK-LABEL: some_alignment: |
| ; CHECK-NEXT: %bb.0: |
| ; |
| ;; prologue |
| ; CHECK-NEXT: push r16 |
| ; CHECK-NEXT: push r17 |
| ; CHECK-NEXT: push r28 |
| ; CHECK-NEXT: push r29 |
| ; CHECK-NEXT: in r28, 61 |
| ; CHECK-NEXT: in r29, 62 |
| ; CHECK-NEXT: sbiw r28, 17 |
| ; CHECK-NEXT: in r0, 63 |
| ; CHECK-NEXT: cli |
| ; CHECK-NEXT: out 62, r29 |
| ; CHECK-NEXT: out 63, r0 |
| ; CHECK-NEXT: out 61, r28 |
| ; |
| ;; SP allocation |
| ; CHECK-NEXT: movw r24, r28 |
| ; CHECK-NEXT: adiw r24, 16 |
| ; CHECK-NEXT: andi r24, 240 |
| ; |
| ;; call void @use (ptr %1) |
| ; CHECK-NEXT: movw r16, r24 |
| ; CHECK-NEXT: movw r24, r16 |
| ; CHECK-NEXT: call use |
| ; |
| ;; %2 = load i16, ptr %1, align 16 |
| ; CHECK-NEXT: movw r30, r16 |
| ; CHECK-NEXT: ld r24, Z |
| ; CHECK-NEXT: ldd r25, Z+1 |
| ; |
| ;; epilogue |
| ; CHECK-NEXT: adiw r28, 17 |
| ; CHECK-NEXT: in r0, 63 |
| ; CHECK-NEXT: cli |
| ; CHECK-NEXT: out 62, r29 |
| ; CHECK-NEXT: out 63, r0 |
| ; CHECK-NEXT: out 61, r28 |
| ; CHECK-NEXT: pop r29 |
| ; CHECK-NEXT: pop r28 |
| ; CHECK-NEXT: pop r17 |
| ; CHECK-NEXT: pop r16 |
| ; CHECK-NEXT: ret |
| |
| %1 = alloca i16, align 16 |
| call void @use(ptr %1) |
| %2 = load i16, ptr %1, align 16 |
| |
| ret i16 %2 |
| } |
| |
| ; Case: One variable with no alignment, another variable with alignment of 16. |
| ; |
| ; This creates two separate stack spaces - an unaligned one (r28:r29) and an |
| ; aligned one (r16:r17). |
| define i16 @mixed_alignment() { |
| ; CHECK-LABEL: mixed_alignment: |
| ; CHECK-NEXT: ; %bb.0: |
| ; |
| ;; prologue |
| ; CHECK-NEXT: push r16 |
| ; CHECK-NEXT: push r17 |
| ; CHECK-NEXT: push r28 |
| ; CHECK-NEXT: push r29 |
| ; CHECK-NEXT: in r28, 61 |
| ; CHECK-NEXT: in r29, 62 |
| ; CHECK-NEXT: sbiw r28, 19 |
| ; CHECK-NEXT: in r0, 63 |
| ; CHECK-NEXT: cli |
| ; CHECK-NEXT: out 62, r29 |
| ; CHECK-NEXT: out 63, r0 |
| ; CHECK-NEXT: out 61, r28 |
| ; |
| ;; SP allocation |
| ; CHECK-NEXT: movw r16, r28 |
| ; CHECK-NEXT: subi r16, 238 |
| ; CHECK-NEXT: sbci r17, 255 |
| ; CHECK-NEXT: andi r16, 240 |
| ; |
| ;; call void @use(ptr %1) |
| ; CHECK-NEXT: movw r24, r28 |
| ; CHECK-NEXT: adiw r24, 1 |
| ; CHECK-NEXT: call use |
| ; |
| ;; call void @use(ptr %2) |
| ; CHECK-NEXT: movw r24, r16 |
| ; CHECK-NEXT: call use |
| ; |
| ;; %4 = load i16, ptr %2, align 16 |
| ; CHECK-NEXT: movw r30, r16 |
| ; CHECK-NEXT: ld r18, Z |
| ; CHECK-NEXT: ldd r19, Z+1 |
| ; |
| ;; %3 = load i16, ptr %1, align 1 |
| ; CHECK-NEXT: ldd r24, Y+1 |
| ; CHECK-NEXT: ldd r25, Y+2 |
| ; |
| ;; %5 = or i16 %3, %4 |
| ; CHECK-NEXT: or r24, r18 |
| ; CHECK-NEXT: or r25, r19 |
| ; |
| ;; epilogue |
| ; CHECK-NEXT: adiw r28, 19 |
| ; CHECK-NEXT: in r0, 63 |
| ; CHECK-NEXT: cli |
| ; CHECK-NEXT: out 62, r29 |
| ; CHECK-NEXT: out 63, r0 |
| ; CHECK-NEXT: out 61, r28 |
| ; CHECK-NEXT: pop r29 |
| ; CHECK-NEXT: pop r28 |
| ; CHECK-NEXT: pop r17 |
| ; CHECK-NEXT: pop r16 |
| ; CHECK-NEXT: ret |
| |
| %1 = alloca i16, align 1 |
| %2 = alloca i16, align 16 |
| |
| call void @use(ptr %1) |
| call void @use(ptr %2) |
| |
| %3 = load i16, ptr %1, align 1 |
| %4 = load i16, ptr %2, align 16 |
| %5 = or i16 %3, %4 |
| |
| ret i16 %5 |
| } |
| |
| ; Case: getelementptr referring to an aligned variable. |
| define i16 @gep() { |
| ; CHECK-LABEL: gep: |
| ; CHECK-NEXT: ; %bb.0: |
| ; |
| ;; prologue |
| ; CHECK-NEXT: push r16 |
| ; CHECK-NEXT: push r17 |
| ; CHECK-NEXT: push r28 |
| ; CHECK-NEXT: push r29 |
| ; CHECK-NEXT: in r28, 61 |
| ; CHECK-NEXT: in r29, 62 |
| ; CHECK-NEXT: sbiw r28, 23 |
| ; CHECK-NEXT: in r0, 63 |
| ; CHECK-NEXT: cli |
| ; CHECK-NEXT: out 62, r29 |
| ; CHECK-NEXT: out 63, r0 |
| ; CHECK-NEXT: out 61, r28 |
| ; |
| ;; SP allocation |
| ; CHECK-NEXT: movw r16, r28 |
| ; CHECK-NEXT: subi r16, 248 |
| ; CHECK-NEXT: sbci r17, 255 |
| ; CHECK-NEXT: andi r16, 248 |
| ; |
| ;; %2 = getelementptr inbounds nuw i8, ptr %1, i16 8 |
| ; CHECK-NEXT: movw r24, r16 |
| ; CHECK-NEXT: adiw r24, 8 |
| ; |
| ;; call void @use(ptr %2) |
| ; CHECK-NEXT: call use |
| ; |
| ;; %3 = getelementptr inbounds nuw i8, ptr %1, i16 8 |
| ; CHECK-NEXT: movw r24, r16 |
| ; CHECK-NEXT: adiw r24, 8 |
| ; |
| ;; %4 = load i16, ptr %3, align 4 |
| ;; ret i16 %4 |
| ; CHECK-NEXT: movw r30, r24 |
| ; CHECK-NEXT: ld r24, Z |
| ; CHECK-NEXT: ldd r25, Z+1 |
| ; CHECK-NEXT: adiw r28, 23 |
| ; |
| ;; epilogue |
| ; CHECK-NEXT: in r0, 63 |
| ; CHECK-NEXT: cli |
| ; CHECK-NEXT: out 62, r29 |
| ; CHECK-NEXT: out 63, r0 |
| ; CHECK-NEXT: out 61, r28 |
| ; CHECK-NEXT: pop r29 |
| ; CHECK-NEXT: pop r28 |
| ; CHECK-NEXT: pop r17 |
| ; CHECK-NEXT: pop r16 |
| ; CHECK-NEXT: ret |
| |
| %1 = alloca [8 x i16], align 8 |
| %2 = getelementptr inbounds nuw i8, ptr %1, i16 8 |
| |
| call void @use(ptr %2) |
| |
| %3 = getelementptr inbounds nuw i8, ptr %1, i16 8 |
| %4 = load i16, ptr %3, align 4 |
| |
| ret i16 %4 |
| } |