[AVR] Add the pseudo instruction expansion pass

Summary:
A lot of the pseudo instructions are required because LLVM assumes that
all integers of the same size as the pointer size are legal. This means
that it will not currently expand 16-bit instructions to their 8-bit
variants because it thinks 16-bit types are legal for the operations.

This also adds all of the CodeGen tests that required the pass to run.

Reviewers: arsenm, kparzysz

Subscribers: wdng, mgorny, modocache, llvm-commits

Differential Revision: https://reviews.llvm.org/D26577

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@287162 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Dylan McKay 2016-11-16 21:58:04 +00:00
parent 9991c32f71
commit d2c33c4ecb
36 changed files with 4412 additions and 1 deletions

File diff suppressed because it is too large Load Diff

View File

@ -106,7 +106,7 @@ void AVRPassConfig::addPreRegAlloc() {
addPass(createAVRDynAllocaSRPass());
}
void AVRPassConfig::addPreSched2() { }
void AVRPassConfig::addPreSched2() { addPass(createAVRExpandPseudoPass()); }
void AVRPassConfig::addPreEmitPass() { }

View File

@ -18,6 +18,7 @@ add_public_tablegen_target(AVRCommonTableGen)
add_llvm_target(AVRCodeGen
AVRAsmPrinter.cpp
AVRExpandPseudoInsts.cpp
AVRFrameLowering.cpp
AVRInstrInfo.cpp
AVRISelDAGToDAG.cpp

93
test/CodeGen/AVR/add.ll Normal file
View File

@ -0,0 +1,93 @@
; RUN: llc -mattr=addsubiw < %s -march=avr | FileCheck %s
define i8 @add8_reg_reg(i8 %a, i8 %b) {
; CHECK-LABEL: add8_reg_reg:
; CHECK: add r24, r22
%result = add i8 %a, %b
ret i8 %result
}
define i8 @add8_reg_imm(i8 %a) {
; CHECK-LABEL: add8_reg_imm:
; CHECK: subi r24, -5
%result = add i8 %a, 5
ret i8 %result
}
define i8 @add8_reg_increment(i8 %a) {
; CHECK-LABEL: add8_reg_increment:
; CHECK: inc r24
%result = add i8 %a, 1
ret i8 %result
}
define i16 @add16_reg_reg(i16 %a, i16 %b) {
; CHECK-LABEL: add16_reg_reg:
; CHECK: add r24, r22
; CHECK: adc r25, r23
%result = add i16 %a, %b
ret i16 %result
}
define i16 @add16_reg_imm(i16 %a) {
; CHECK-LABEL: add16_reg_imm:
; CHECK: adiw r24, 63
%result = add i16 %a, 63
ret i16 %result
}
define i16 @add16_reg_imm_subi(i16 %a) {
; CHECK-LABEL: add16_reg_imm_subi:
; CHECK: subi r24, 133
; CHECK: sbci r25, 255
%result = add i16 %a, 123
ret i16 %result
}
define i32 @add32_reg_reg(i32 %a, i32 %b) {
; CHECK-LABEL: add32_reg_reg:
; CHECK: add r22, r18
; CHECK: adc r23, r19
; CHECK: adc r24, r20
; CHECK: adc r25, r21
%result = add i32 %a, %b
ret i32 %result
}
define i32 @add32_reg_imm(i32 %a) {
; CHECK-LABEL: add32_reg_imm:
; CHECK: subi r22, 251
; CHECK: sbci r23, 255
; CHECK: sbci r24, 255
; CHECK: sbci r25, 255
%result = add i32 %a, 5
ret i32 %result
}
define i64 @add64_reg_reg(i64 %a, i64 %b) {
; CHECK-LABEL: add64_reg_reg:
; CHECK: add r18, r10
; CHECK: adc r20, r12
; CHECK: adc r21, r13
; CHECK: adc r22, r14
; CHECK: adc r23, r15
; CHECK: adc r24, r16
; CHECK: adc r25, r17
%result = add i64 %a, %b
ret i64 %result
}
define i64 @add64_reg_imm(i64 %a) {
; CHECK-LABEL: add64_reg_imm:
; CHECK: subi r18, 251
; CHECK: sbci r19, 255
; CHECK: sbci r20, 255
; CHECK: sbci r21, 255
; CHECK: sbci r22, 255
; CHECK: sbci r23, 255
; CHECK: sbci r24, 255
; CHECK: sbci r25, 255
%result = add i64 %a, 5
ret i64 %result
}

View File

@ -0,0 +1,84 @@
; RUN: llc < %s -march=avr -mattr=avr6 | FileCheck %s
declare i16 @allocate(i16*, i16*)
; Test taking an address of an alloca with a small offset (adiw)
define i16 @alloca_addressof_small() {
entry:
; CHECK-LABEL: alloca_addressof_small:
; Test that Y is saved
; CHECK: push r28
; CHECK: push r29
; CHECK: movw r24, r28
; CHECK: adiw r24, 17
; CHECK: movw {{.*}}, r28
; CHECK: adiw {{.*}}, 39
; CHECK: movw r22, {{.*}}
; CHECK: pop r29
; CHECK: pop r28
%p = alloca [18 x i16]
%k = alloca [14 x i16]
%arrayidx = getelementptr inbounds [14 x i16], [14 x i16]* %k, i16 0, i16 8
%arrayidx1 = getelementptr inbounds [18 x i16], [18 x i16]* %p, i16 0, i16 5
%call = call i16 @allocate(i16* %arrayidx, i16* %arrayidx1)
ret i16 %call
}
; Test taking an address of an alloca with a big offset (subi/sbci pair)
define i16 @alloca_addressof_big() {
entry:
; CHECK-LABEL: alloca_addressof_big:
; CHECK: movw r24, r28
; CHECK: adiw r24, 17
; CHECK: movw r22, r28
; CHECK: subi r22, 145
; CHECK: sbci r23, 255
%p = alloca [55 x i16]
%k = alloca [14 x i16]
%arrayidx = getelementptr inbounds [14 x i16], [14 x i16]* %k, i16 0, i16 8
%arrayidx1 = getelementptr inbounds [55 x i16], [55 x i16]* %p, i16 0, i16 41
%call = call i16 @allocate(i16* %arrayidx, i16* %arrayidx1)
ret i16 %call
}
; Test writing to an allocated variable with a small and a big offset
define i16 @alloca_write(i16 %x) {
entry:
; CHECK-LABEL: alloca_write:
; Big offset here
; CHECK: adiw r28, 57
; CHECK: std Y+62, {{.*}}
; CHECK: std Y+63, {{.*}}
; CHECK: sbiw r28, 57
; Small offset here
; CHECK: std Y+23, {{.*}}
; CHECK: std Y+24, {{.*}}
%p = alloca [15 x i16]
%k = alloca [14 x i16]
%arrayidx = getelementptr inbounds [15 x i16], [15 x i16]* %p, i16 0, i16 45
store i16 22, i16* %arrayidx
%arrayidx1 = getelementptr inbounds [14 x i16], [14 x i16]* %k, i16 0, i16 11
store i16 42, i16* %arrayidx1
%arrayidx2 = getelementptr inbounds [14 x i16], [14 x i16]* %k, i16 0, i16 0
%arrayidx3 = getelementptr inbounds [15 x i16], [15 x i16]* %p, i16 0, i16 0
%call = call i16 @allocate(i16* %arrayidx2, i16* %arrayidx3)
ret i16 %call
}
; Test writing to an allocated variable with a huge offset that cant be
; materialized with adiw/sbiw but with a subi/sbci pair.
define void @alloca_write_huge() {
; CHECK-LABEL: alloca_write_huge:
; CHECK: subi r28, 41
; CHECK: sbci r29, 255
; CHECK: std Y+62, {{.*}}
; CHECK: std Y+63, {{.*}}
; CHECK: subi r28, 215
; CHECK: sbci r29, 0
%k = alloca [140 x i16]
%arrayidx = getelementptr inbounds [140 x i16], [140 x i16]* %k, i16 0, i16 138
store i16 22, i16* %arrayidx
%arraydecay = getelementptr inbounds [140 x i16], [140 x i16]* %k, i16 0, i16 0
call i16 @allocate(i16* %arraydecay, i16* null)
ret void
}

80
test/CodeGen/AVR/and.ll Normal file
View File

@ -0,0 +1,80 @@
; RUN: llc < %s -march=avr | FileCheck %s
define i8 @and8_reg_reg(i8 %a, i8 %b) {
; CHECK-LABEL: and8_reg_reg:
; CHECK: and r24, r22
%result = and i8 %a, %b
ret i8 %result
}
define i8 @and8_reg_imm(i8 %a) {
; CHECK-LABEL: and8_reg_imm:
; CHECK: andi r24, 5
%result = and i8 %a, 5
ret i8 %result
}
define i16 @and16_reg_reg(i16 %a, i16 %b) {
; CHECK-LABEL: and16_reg_reg:
; CHECK: and r24, r22
; CHECK: and r25, r23
%result = and i16 %a, %b
ret i16 %result
}
define i16 @and16_reg_imm(i16 %a) {
; CHECK-LABEL: and16_reg_imm:
; CHECK: andi r24, 210
; CHECK: andi r25, 4
%result = and i16 %a, 1234
ret i16 %result
}
define i32 @and32_reg_reg(i32 %a, i32 %b) {
; CHECK-LABEL: and32_reg_reg:
; CHECK: and r22, r18
; CHECK: and r23, r19
; CHECK: and r24, r20
; CHECK: and r25, r21
%result = and i32 %a, %b
ret i32 %result
}
define i32 @and32_reg_imm(i32 %a) {
; CHECK-LABEL: and32_reg_imm:
; CHECK: andi r22, 21
; CHECK: andi r23, 205
; CHECK: andi r24, 91
; CHECK: andi r25, 7
%result = and i32 %a, 123456789
ret i32 %result
}
define i64 @and64_reg_reg(i64 %a, i64 %b) {
; CHECK-LABEL: and64_reg_reg:
; CHECK: and r18, r10
; CHECK: and r19, r11
; CHECK: and r20, r12
; CHECK: and r21, r13
; CHECK: and r22, r14
; CHECK: and r23, r15
; CHECK: and r24, r16
; CHECK: and r25, r17
%result = and i64 %a, %b
ret i64 %result
}
define i64 @and64_reg_imm(i64 %a) {
; CHECK-LABEL: and64_reg_imm:
; CHECK: andi r18, 253
; CHECK: andi r19, 255
; CHECK: andi r20, 155
; CHECK: andi r21, 88
; CHECK: andi r22, 76
; CHECK: andi r23, 73
; CHECK: andi r24, 31
; CHECK: andi r25, 242
%result = and i64 %a, 17446744073709551613
ret i64 %result
}

View File

@ -0,0 +1,13 @@
; RUN: llc -mattr=avr6 < %s -march=avr | FileCheck %s
; Checks that atomic fences are simply removed from IR.
; AVR is always singlethreaded so fences do nothing.
; CHECK_LABEL: atomic_fence8
; CHECK: ; BB#0:
; CHECK-NEXT: ret
define void @atomic_fence8() {
fence acquire
ret void
}

View File

@ -0,0 +1,137 @@
; RUN: llc -mattr=avr6 < %s -march=avr | FileCheck %s
; CHECK-LABEL: atomic_load16
; CHECK: in r0, 63
; CHECK-NEXT: cli
; CHECK-NEXT: ld [[RR:r[0-9]+]], [[RD:(X|Y|Z)]]
; CHECK-NEXT: ldd [[RR:r[0-9]+]], [[RD:(X|Y|Z)]]+
; CHECK-NEXT: out 63, r0
define i16 @atomic_load16(i16* %foo) {
%val = load atomic i16, i16* %foo unordered, align 2
ret i16 %val
}
; CHECK-LABEL: atomic_load_swap16
; CHECK: call __sync_lock_test_and_set_2
define i16 @atomic_load_swap16(i16* %foo) {
%val = atomicrmw xchg i16* %foo, i16 13 seq_cst
ret i16 %val
}
; CHECK-LABEL: atomic_load_cmp_swap16
; CHECK: call __sync_val_compare_and_swap_2
define i16 @atomic_load_cmp_swap16(i16* %foo) {
%val = cmpxchg i16* %foo, i16 5, i16 10 acq_rel monotonic
%value_loaded = extractvalue { i16, i1 } %val, 0
ret i16 %value_loaded
}
; CHECK-LABEL: atomic_load_add16
; CHECK: in r0, 63
; CHECK-NEXT: cli
; CHECK-NEXT: ld [[RR1:r[0-9]+]], [[RD1:(X|Y|Z)]]
; CHECK-NEXT: ldd [[RR2:r[0-9]+]], [[RD2:(X|Y|Z)]]+
; CHECK-NEXT: add [[RR1]], [[TMP:r[0-9]+]]
; CHECK-NEXT: adc [[RR2]], [[TMP:r[0-9]+]]
; CHECK-NEXT: st [[RD1]], [[RR1]]
; CHECK-NEXT: std [[RD1]]+1, [[A:r[0-9]+]]
; CHECK-NEXT: out 63, r0
define i16 @atomic_load_add16(i16* %foo) {
%val = atomicrmw add i16* %foo, i16 13 seq_cst
ret i16 %val
}
; CHECK-LABEL: atomic_load_sub16
; CHECK: in r0, 63
; CHECK-NEXT: cli
; CHECK-NEXT: ld [[RR1:r[0-9]+]], [[RD1:(X|Y|Z)]]
; CHECK-NEXT: ldd [[RR2:r[0-9]+]], [[RD2:(X|Y|Z)]]+
; CHECK-NEXT: sub [[RR1]], [[TMP:r[0-9]+]]
; CHECK-NEXT: sbc [[RR2]], [[TMP:r[0-9]+]]
; CHECK-NEXT: st [[RD1]], [[RR1]]
; CHECK-NEXT: std [[RD1]]+1, [[A:r[0-9]+]]
; CHECK-NEXT: out 63, r0
define i16 @atomic_load_sub16(i16* %foo) {
%val = atomicrmw sub i16* %foo, i16 13 seq_cst
ret i16 %val
}
; CHECK-LABEL: atomic_load_and16
; CHECK: in r0, 63
; CHECK-NEXT: cli
; CHECK-NEXT: ld [[RR1:r[0-9]+]], [[RD1:(X|Y|Z)]]
; CHECK-NEXT: ldd [[RR2:r[0-9]+]], [[RD2:(X|Y|Z)]]+
; CHECK-NEXT: and [[RR1]], [[TMP:r[0-9]+]]
; CHECK-NEXT: and [[RR2]], [[TMP:r[0-9]+]]
; CHECK-NEXT: st [[RD1]], [[RR1]]
; CHECK-NEXT: std [[RD1]]+1, [[A:r[0-9]+]]
; CHECK-NEXT: out 63, r0
define i16 @atomic_load_and16(i16* %foo) {
%val = atomicrmw and i16* %foo, i16 13 seq_cst
ret i16 %val
}
; CHECK-LABEL: atomic_load_or16
; CHECK: in r0, 63
; CHECK-NEXT: cli
; CHECK-NEXT: ld [[RR1:r[0-9]+]], [[RD1:(X|Y|Z)]]
; CHECK-NEXT: ldd [[RR2:r[0-9]+]], [[RD2:(X|Y|Z)]]+
; CHECK-NEXT: or [[RR1]], [[TMP:r[0-9]+]]
; CHECK-NEXT: or [[RR2]], [[TMP:r[0-9]+]]
; CHECK-NEXT: st [[RD1]], [[RR1]]
; CHECK-NEXT: std [[RD1]]+1, [[A:r[0-9]+]]
; CHECK-NEXT: out 63, r0
define i16 @atomic_load_or16(i16* %foo) {
%val = atomicrmw or i16* %foo, i16 13 seq_cst
ret i16 %val
}
; CHECK-LABEL: atomic_load_xor16
; CHECK: in r0, 63
; CHECK-NEXT: cli
; CHECK-NEXT: ld [[RR1:r[0-9]+]], [[RD1:(X|Y|Z)]]
; CHECK-NEXT: ldd [[RR2:r[0-9]+]], [[RD2:(X|Y|Z)]]+
; CHECK-NEXT: eor [[RR1]], [[TMP:r[0-9]+]]
; CHECK-NEXT: eor [[RR2]], [[TMP:r[0-9]+]]
; CHECK-NEXT: st [[RD1]], [[RR1]]
; CHECK-NEXT: std [[RD1]]+1, [[A:r[0-9]+]]
; CHECK-NEXT: out 63, r0
define i16 @atomic_load_xor16(i16* %foo) {
%val = atomicrmw xor i16* %foo, i16 13 seq_cst
ret i16 %val
}
; CHECK-LABEL: atomic_load_nand16
; CHECK: call __sync_fetch_and_nand_2
define i16 @atomic_load_nand16(i16* %foo) {
%val = atomicrmw nand i16* %foo, i16 13 seq_cst
ret i16 %val
}
; CHECK-LABEL: atomic_load_max16
; CHECK: call __sync_fetch_and_max_2
define i16 @atomic_load_max16(i16* %foo) {
%val = atomicrmw max i16* %foo, i16 13 seq_cst
ret i16 %val
}
; CHECK-LABEL: atomic_load_min16
; CHECK: call __sync_fetch_and_min_2
define i16 @atomic_load_min16(i16* %foo) {
%val = atomicrmw min i16* %foo, i16 13 seq_cst
ret i16 %val
}
; CHECK-LABEL: atomic_load_umax16
; CHECK: call __sync_fetch_and_umax_2
define i16 @atomic_load_umax16(i16* %foo) {
%val = atomicrmw umax i16* %foo, i16 13 seq_cst
ret i16 %val
}
; CHECK-LABEL: atomic_load_umin16
; CHECK: call __sync_fetch_and_umin_2
define i16 @atomic_load_umin16(i16* %foo) {
%val = atomicrmw umin i16* %foo, i16 13 seq_cst
ret i16 %val
}

View File

@ -0,0 +1,124 @@
; RUN: llc -mattr=avr6 < %s -march=avr | FileCheck %s
; Tests atomic operations on AVR
; CHECK-LABEL: atomic_load8
; CHECK: in r0, 63
; CHECK-NEXT: cli
; CHECK-NEXT: ld [[RR:r[0-9]+]], [[RD:(X|Y|Z)]]
; CHECK-NEXT: out 63, r0
define i8 @atomic_load8(i8* %foo) {
%val = load atomic i8, i8* %foo unordered, align 1
ret i8 %val
}
; CHECK-LABEL: atomic_load_swap8
; CHECK: call __sync_lock_test_and_set_1
define i8 @atomic_load_swap8(i8* %foo) {
%val = atomicrmw xchg i8* %foo, i8 13 seq_cst
ret i8 %val
}
; CHECK-LABEL: atomic_load_cmp_swap8
; CHECK: call __sync_val_compare_and_swap_1
define i8 @atomic_load_cmp_swap8(i8* %foo) {
%val = cmpxchg i8* %foo, i8 5, i8 10 acq_rel monotonic
%value_loaded = extractvalue { i8, i1 } %val, 0
ret i8 %value_loaded
}
; CHECK-LABEL: atomic_load_add8
; CHECK: in r0, 63
; CHECK-NEXT: cli
; CHECK-NEXT: ld [[RD:r[0-9]+]], [[RR:(X|Y|Z)]]
; CHECK-NEXT: add [[RD]], [[RR1:r[0-9]+]]
; CHECK-NEXT: st [[RR]], [[RD]]
; CHECK-NEXT: out 63, r0
define i8 @atomic_load_add8(i8* %foo) {
%val = atomicrmw add i8* %foo, i8 13 seq_cst
ret i8 %val
}
; CHECK-LABEL: atomic_load_sub8
; CHECK: in r0, 63
; CHECK-NEXT: cli
; CHECK-NEXT: ld [[RD:r[0-9]+]], [[RR:(X|Y|Z)]]
; CHECK-NEXT: sub [[RD]], [[RR1:r[0-9]+]]
; CHECK-NEXT: st [[RR]], [[RD]]
; CHECK-NEXT: out 63, r0
define i8 @atomic_load_sub8(i8* %foo) {
%val = atomicrmw sub i8* %foo, i8 13 seq_cst
ret i8 %val
}
; CHECK-LABEL: atomic_load_and8
; CHECK: in r0, 63
; CHECK-NEXT: cli
; CHECK-NEXT: ld [[RD:r[0-9]+]], [[RR:(X|Y|Z)]]
; CHECK-NEXT: and [[RD]], [[RR1:r[0-9]+]]
; CHECK-NEXT: st [[RR]], [[RD]]
; CHECK-NEXT: out 63, r0
define i8 @atomic_load_and8(i8* %foo) {
%val = atomicrmw and i8* %foo, i8 13 seq_cst
ret i8 %val
}
; CHECK-LABEL: atomic_load_or8
; CHECK: in r0, 63
; CHECK-NEXT: cli
; CHECK-NEXT: ld [[RD:r[0-9]+]], [[RR:(X|Y|Z)]]
; CHECK-NEXT: or [[RD]], [[RR1:r[0-9]+]]
; CHECK-NEXT: st [[RR]], [[RD]]
; CHECK-NEXT: out 63, r0
define i8 @atomic_load_or8(i8* %foo) {
%val = atomicrmw or i8* %foo, i8 13 seq_cst
ret i8 %val
}
; CHECK-LABEL: atomic_load_xor8
; CHECK: in r0, 63
; CHECK-NEXT: cli
; CHECK-NEXT: ld [[RD:r[0-9]+]], [[RR:(X|Y|Z)]]
; CHECK-NEXT: eor [[RD]], [[RR1:r[0-9]+]]
; CHECK-NEXT: st [[RR]], [[RD]]
; CHECK-NEXT: out 63, r0
define i8 @atomic_load_xor8(i8* %foo) {
%val = atomicrmw xor i8* %foo, i8 13 seq_cst
ret i8 %val
}
; CHECK-LABEL: atomic_load_nand8
; CHECK: call __sync_fetch_and_nand_1
define i8 @atomic_load_nand8(i8* %foo) {
%val = atomicrmw nand i8* %foo, i8 13 seq_cst
ret i8 %val
}
; CHECK-LABEL: atomic_load_max8
; CHECK: call __sync_fetch_and_max_1
define i8 @atomic_load_max8(i8* %foo) {
%val = atomicrmw max i8* %foo, i8 13 seq_cst
ret i8 %val
}
; CHECK-LABEL: atomic_load_min8
; CHECK: call __sync_fetch_and_min_1
define i8 @atomic_load_min8(i8* %foo) {
%val = atomicrmw min i8* %foo, i8 13 seq_cst
ret i8 %val
}
; CHECK-LABEL: atomic_load_umax8
; CHECK: call __sync_fetch_and_umax_1
define i8 @atomic_load_umax8(i8* %foo) {
%val = atomicrmw umax i8* %foo, i8 13 seq_cst
ret i8 %val
}
; CHECK-LABEL: atomic_load_umin8
; CHECK: call __sync_fetch_and_umin_1
define i8 @atomic_load_umin8(i8* %foo) {
%val = atomicrmw umin i8* %foo, i8 13 seq_cst
ret i8 %val
}

View File

@ -0,0 +1,37 @@
; RUN: llc -mattr=avr6 < %s -march=avr | FileCheck %s
; CHECK-LABEL: atomic_store8
; CHECK: in r0, 63
; CHECK-NEXT: cli
; CHECK-NEXT: st [[RD:(X|Y|Z)]], [[RR:r[0-9]+]]
; CHECK-NEXT: out 63, r0
define void @atomic_store8(i8* %foo) {
store atomic i8 1, i8* %foo unordered, align 1
ret void
}
; CHECK-LABEL: atomic_store16
; CHECK: in r0, 63
; CHECK-NEXT: cli
; CHECK-NEXT: st [[RD:(X|Y|Z)]], [[RR:r[0-9]+]]
; CHECK-NEXT: std [[RD]]+1, [[RR:r[0-9]+]]
; CHECK-NEXT: out 63, r0
define void @atomic_store16(i16* %foo) {
store atomic i16 1, i16* %foo unordered, align 2
ret void
}
; CHECK-LABEL: atomic_store32
; CHECK: call __sync_lock_test_and_set_4
define void @atomic_store32(i32* %foo) {
store atomic i32 1, i32* %foo unordered, align 4
ret void
}
; CHECK-LABEL: atomic_store64
; CHECK: call __sync_lock_test_and_set_8
define void @atomic_store64(i64* %foo) {
store atomic i64 1, i64* %foo unordered, align 8
ret void
}

View File

@ -0,0 +1,25 @@
; RUN: llc -mattr=avr6 < %s -march=avr | FileCheck %s
; CHECK-LABEL: atomic_store16
; CHECK: in r0, 63
; CHECK-NEXT: cli
; CHECK-NEXT: st [[RD:(X|Y|Z)]], [[RR:r[0-9]+]]
; CHECK-NEXT: std [[RD:(X|Y|Z)]]+1, [[RR:r[0-9]+]]
; CHECK-NEXT: out 63, r0
define void @atomic_store16(i16* %foo) {
store atomic i16 1, i16* %foo unordered, align 2
ret void
}
; CHECK-LABEL: monotonic
; CHECK: in r0, 63
; CHECK-NEXT: cli
; CHECK-NEXT: st Z, r24
; CHECK-NEXT: std Z+1, r25
; CHECK-NEXT: out 63, r0
define void @monotonic(i16) {
entry-block:
store atomic i16 %0, i16* undef monotonic, align 2
ret void
}

20
test/CodeGen/AVR/brind.ll Normal file
View File

@ -0,0 +1,20 @@
; RUN: llc -mattr=sram,eijmpcall < %s -march=avr | FileCheck %s
@brind.k = private unnamed_addr constant [2 x i8*] [i8* blockaddress(@brind, %return), i8* blockaddress(@brind, %b)], align 1
define i8 @brind(i8 %p) {
; CHECK-LABEL: brind:
; CHECK: ld r30
; CHECK: ldd r31
; CHECK: ijmp
entry:
%idxprom = sext i8 %p to i16
%arrayidx = getelementptr inbounds [2 x i8*], [2 x i8*]* @brind.k, i16 0, i16 %idxprom
%s = load i8*, i8** %arrayidx
indirectbr i8* %s, [label %return, label %b]
b:
br label %return
return:
%retval.0 = phi i8 [ 4, %b ], [ 2, %entry ]
ret i8 %retval.0
}

211
test/CodeGen/AVR/call.ll Normal file
View File

@ -0,0 +1,211 @@
; RUN: llc < %s -march=avr -mattr=avr6 | FileCheck %s
; TODO: test returning byval structs
declare i8 @foo8_1(i8)
declare i8 @foo8_2(i8, i8, i8)
declare i8 @foo8_3(i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8)
declare i16 @foo16_1(i16, i16)
declare i16 @foo16_2(i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16)
declare i32 @foo32_1(i32, i32)
declare i32 @foo32_2(i32, i32, i32, i32, i32)
declare i64 @foo64_1(i64)
declare i64 @foo64_2(i64, i64, i64)
define i8 @calli8_reg() {
; CHECK-LABEL: calli8_reg:
; CHECK: ldi r24, 12
; CHECK: call foo8_1
; CHECK: ldi r24, 12
; CHECK: ldi r22, 13
; CHECK: ldi r20, 14
; CHECK: call foo8_2
%result1 = call i8 @foo8_1(i8 12)
%result2 = call i8 @foo8_2(i8 12, i8 13, i8 14)
ret i8 %result2
}
define i8 @calli8_stack() {
; CHECK-LABEL: calli8_stack:
; CHECK: ldi [[REG1:r[0-9]+]], 11
; CHECK: push [[REG1]]
; CHECK: ldi [[REG1]], 10
; CHECK: push [[REG1]]
; CHECK: call foo8_3
%result1 = call i8 @foo8_3(i8 1, i8 2, i8 3, i8 4, i8 5, i8 6, i8 7, i8 8, i8 9, i8 10, i8 11)
ret i8 %result1
}
define i16 @calli16_reg() {
; CHECK-LABEL: calli16_reg:
; CHECK: ldi r24, 1
; CHECK: ldi r25, 2
; CHECK: ldi r22, 2
; CHECK: ldi r23, 2
; CHECK: call foo16_1
%result1 = call i16 @foo16_1(i16 513, i16 514)
ret i16 %result1
}
define i16 @calli16_stack() {
; CHECK-LABEL: calli16_stack:
; CHECK: ldi [[REG1:r[0-9]+]], 10
; CHECK: ldi [[REG2:r[0-9]+]], 2
; CHECK: push [[REG2]]
; CHECK: push [[REG1]]
; CHECK: ldi [[REG1:r[0-9]+]], 9
; CHECK: ldi [[REG2:r[0-9]+]], 2
; CHECK: push [[REG2]]
; CHECK: push [[REG1]]
; CHECK: call foo16_2
%result1 = call i16 @foo16_2(i16 512, i16 513, i16 514, i16 515, i16 516, i16 517, i16 518, i16 519, i16 520, i16 521, i16 522)
ret i16 %result1
}
define i32 @calli32_reg() {
; CHECK-LABEL: calli32_reg:
; CHECK: ldi r22, 64
; CHECK: ldi r23, 66
; CHECK: ldi r24, 15
; CHECK: ldi r25, 2
; CHECK: ldi r18, 128
; CHECK: ldi r19, 132
; CHECK: ldi r20, 30
; CHECK: ldi r21, 2
; CHECK: call foo32_1
%result1 = call i32 @foo32_1(i32 34554432, i32 35554432)
ret i32 %result1
}
define i32 @calli32_stack() {
; CHECK-LABEL: calli32_stack:
; CHECK: ldi [[REG1:r[0-9]+]], 15
; CHECK: ldi [[REG2:r[0-9]+]], 2
; CHECK: push [[REG2]]
; CHECK: push [[REG1]]
; CHECK: ldi [[REG1:r[0-9]+]], 64
; CHECK: ldi [[REG2:r[0-9]+]], 66
; CHECK: push [[REG2]]
; CHECK: push [[REG1]]
; CHECK: call foo32_2
%result1 = call i32 @foo32_2(i32 1, i32 2, i32 3, i32 4, i32 34554432)
ret i32 %result1
}
define i64 @calli64_reg() {
; CHECK-LABEL: calli64_reg:
; CHECK: ldi r18, 255
; CHECK: ldi r19, 255
; CHECK: ldi r20, 155
; CHECK: ldi r21, 88
; CHECK: ldi r22, 76
; CHECK: ldi r23, 73
; CHECK: ldi r24, 31
; CHECK: ldi r25, 242
; CHECK: call foo64_1
%result1 = call i64 @foo64_1(i64 17446744073709551615)
ret i64 %result1
}
define i64 @calli64_stack() {
; CHECK-LABEL: calli64_stack:
; CHECK: ldi [[REG1:r[0-9]+]], 31
; CHECK: ldi [[REG2:r[0-9]+]], 242
; CHECK: push [[REG2]]
; CHECK: push [[REG1]]
; CHECK: ldi [[REG1:r[0-9]+]], 76
; CHECK: ldi [[REG2:r[0-9]+]], 73
; CHECK: push [[REG2]]
; CHECK: push [[REG1]]
; CHECK: ldi [[REG1:r[0-9]+]], 155
; CHECK: ldi [[REG2:r[0-9]+]], 88
; CHECK: push [[REG2]]
; CHECK: push [[REG1]]
; CHECK: ldi [[REG1:r[0-9]+]], 255
; CHECK: ldi [[REG2:r[0-9]+]], 255
; CHECK: push [[REG2]]
; CHECK: push [[REG1]]
; CHECK: call foo64_2
%result1 = call i64 @foo64_2(i64 1, i64 2, i64 17446744073709551615)
ret i64 %result1
}
; Test passing arguments through the stack when the call frame is allocated
; in the prologue.
declare void @foo64_3(i64, i64, i64, i8, i16*)
define void @testcallprologue() {
; CHECK-LABEL: testcallprologue:
; CHECK: push r28
; CHECK: push r29
; CHECK: sbiw r28, 28
; CHECK: ldi [[REG1:r[0-9]+]], 88
; CHECK: std Y+9, [[REG1]]
; CHECK: ldi [[REG1:r[0-9]+]], 11
; CHECK: ldi [[REG2:r[0-9]+]], 10
; CHECK: std Y+7, [[REG1]]
; CHECK: std Y+8, [[REG2]]
; CHECK: ldi [[REG1:r[0-9]+]], 13
; CHECK: ldi [[REG2:r[0-9]+]], 12
; CHECK: std Y+5, [[REG1]]
; CHECK: std Y+6, [[REG2]]
; CHECK: ldi [[REG1:r[0-9]+]], 15
; CHECK: ldi [[REG2:r[0-9]+]], 14
; CHECK: std Y+3, [[REG1]]
; CHECK: std Y+4, [[REG2]]
; CHECK: ldi [[REG1:r[0-9]+]], 8
; CHECK: ldi [[REG2:r[0-9]+]], 9
; CHECK: std Y+1, [[REG1]]
; CHECK: std Y+2, [[REG2]]
; CHECK: pop r29
; CHECK: pop r28
%p = alloca [8 x i16]
%arraydecay = getelementptr inbounds [8 x i16], [8 x i16]* %p, i16 0, i16 0
call void @foo64_3(i64 723685415333071112, i64 723685415333071112, i64 723685415333071112, i8 88, i16* %arraydecay)
ret void
}
define i32 @icall(i32 (i32)* %foo) {
; CHECK-LABEL: icall:
; CHECK: movw [[REG:r[0-9]+]], r24
; CHECK: ldi r22, 147
; CHECK: ldi r23, 248
; CHECK: ldi r24, 214
; CHECK: ldi r25, 198
; CHECK: movw r30, [[REG]]
; CHECK: icall
; CHECK: subi r22, 251
; CHECK: sbci r23, 255
; CHECK: sbci r24, 255
; CHECK: sbci r25, 255
%1 = call i32 %foo(i32 3335977107)
%2 = add nsw i32 %1, 5
ret i32 %2
}
; Calling external functions (like __divsf3) require extra processing for
; arguments and return values in the LowerCall function.
declare i32 @foofloat(float)
define i32 @externcall(float %a, float %b) {
; CHECK-LABEL: externcall:
; CHECK: movw [[REG1:(r[0-9]+|[XYZ])]], r24
; CHECK: movw [[REG2:(r[0-9]+|[XYZ])]], r22
; CHECK: movw r22, r18
; CHECK: movw r24, r20
; CHECK: movw r18, [[REG2]]
; CHECK: movw r20, [[REG1]]
; CHECK: call __divsf3
; CHECK: call foofloat
; CHECK: subi r22, 251
; CHECK: sbci r23, 255
; CHECK: sbci r24, 255
; CHECK: sbci r25, 255
%1 = fdiv float %b, %a
%2 = call i32 @foofloat(float %1)
%3 = add nsw i32 %2, 5
ret i32 %3
}

148
test/CodeGen/AVR/cmp.ll Normal file
View File

@ -0,0 +1,148 @@
; RUN: llc < %s -march=avr | FileCheck %s
declare void @f1(i8)
declare void @f2(i8)
define void @cmp8(i8 %a, i8 %b) {
; CHECK-LABEL: cmp8:
; CHECK: cp
; CHECK-NOT: cpc
%cmp = icmp eq i8 %a, %b
br i1 %cmp, label %if.then, label %if.else
if.then:
tail call void @f1(i8 %a)
br label %if.end
if.else:
tail call void @f2(i8 %b)
br label %if.end
if.end:
ret void
}
declare void @f3(i16)
declare void @f4(i16)
define void @cmp16(i16 %a, i16 %b) {
; CHECK-LABEL: cmp16:
; CHECK: cp
; CHECK-NEXT: cpc
%cmp = icmp eq i16 %a, %b
br i1 %cmp, label %if.then, label %if.else
if.then:
tail call void @f3(i16 %a)
br label %if.end
if.else:
tail call void @f4(i16 %b)
br label %if.end
if.end:
ret void
}
declare void @f5(i32)
declare void @f6(i32)
define void @cmp32(i32 %a, i32 %b) {
; CHECK-LABEL: cmp32:
; CHECK: cp
; CHECK-NEXT: cpc
; CHECK-NEXT: cpc
; CHECK-NEXT: cpc
%cmp = icmp eq i32 %a, %b
br i1 %cmp, label %if.then, label %if.else
if.then:
tail call void @f5(i32 %a)
br label %if.end
if.else:
tail call void @f6(i32 %b)
br label %if.end
if.end:
ret void
}
declare void @f7(i64)
declare void @f8(i64)
define void @cmp64(i64 %a, i64 %b) {
; CHECK-LABEL: cmp64:
; CHECK: cp
; CHECK-NEXT: cpc
; CHECK-NEXT: cpc
; CHECK-NEXT: cpc
; CHECK-NEXT: cpc
; CHECK-NEXT: cpc
; CHECK-NEXT: cpc
; CHECK-NEXT: cpc
%cmp = icmp eq i64 %a, %b
br i1 %cmp, label %if.then, label %if.else
if.then:
tail call void @f7(i64 %a)
br label %if.end
if.else:
tail call void @f8(i64 %b)
br label %if.end
if.end:
ret void
}
declare void @f9()
declare void @f10()
define void @tst8(i8 %a) {
; CHECK-LABEL: tst8:
; CHECK: tst r24
; CHECK-NEXT: brmi
%cmp = icmp sgt i8 %a, -1
br i1 %cmp, label %if.then, label %if.else
if.then:
tail call void @f9()
br label %if.end
if.else:
tail call void @f10()
br label %if.end
if.end:
ret void
}
define void @tst16(i16 %a) {
; CHECK-LABEL: tst16:
; CHECK: tst r25
; CHECK-NEXT: brmi
%cmp = icmp sgt i16 %a, -1
br i1 %cmp, label %if.then, label %if.else
if.then:
tail call void @f9()
br label %if.end
if.else:
tail call void @f10()
br label %if.end
if.end:
ret void
}
define void @tst32(i32 %a) {
; CHECK-LABEL: tst32:
; CHECK: tst r25
; CHECK-NEXT: brmi
%cmp = icmp sgt i32 %a, -1
br i1 %cmp, label %if.then, label %if.else
if.then:
tail call void @f9()
br label %if.end
if.else:
tail call void @f10()
br label %if.end
if.end:
ret void
}
define void @tst64(i64 %a) {
; CHECK-LABEL: tst64:
; CHECK: tst r25
; CHECK-NEXT: brmi
%cmp = icmp sgt i64 %a, -1
br i1 %cmp, label %if.then, label %if.else
if.then:
tail call void @f9()
br label %if.end
if.else:
tail call void @f10()
br label %if.end
if.end:
ret void
}

40
test/CodeGen/AVR/com.ll Normal file
View File

@ -0,0 +1,40 @@
; RUN: llc < %s -march=avr | FileCheck %s
define i8 @com8(i8 %x) {
; CHECK-LABEL: com8:
; CHECK: com r24
%neg = xor i8 %x, -1
ret i8 %neg
}
define i16 @com16(i16 %x) {
; CHECK-LABEL: com16:
; CHECK: com r24
; CHECK: com r25
%neg = xor i16 %x, -1
ret i16 %neg
}
define i32 @com32(i32 %x) {
; CHECK-LABEL: com32:
; CHECK: com r22
; CHECK: com r23
; CHECK: com r24
; CHECK: com r25
%neg = xor i32 %x, -1
ret i32 %neg
}
define i64 @com64(i64 %x) {
; CHECK-LABEL: com64:
; CHECK: com r18
; CHECK: com r19
; CHECK: com r20
; CHECK: com r21
; CHECK: com r22
; CHECK: com r23
; CHECK: com r24
; CHECK: com r25
%neg = xor i64 %x, -1
ret i64 %neg
}

View File

@ -0,0 +1,345 @@
; RUN: llc -mattr=sram,addsubiw < %s -march=avr | FileCheck %s
@char = common global i8 0
@char.array = common global [3 x i8] zeroinitializer
@char.static = internal global i8 0
@int = common global i16 0
@int.array = common global [3 x i16] zeroinitializer
@int.static = internal global i16 0
@long = common global i32 0
@long.array = common global [3 x i32] zeroinitializer
@long.static = internal global i32 0
@longlong = common global i64 0
@longlong.array = common global [3 x i64] zeroinitializer
@longlong.static = internal global i64 0
define void @global8_store() {
; CHECK-LABEL: global8_store:
; CHECK: ldi [[REG:r[0-9]+]], 6
; CHECK: sts char, [[REG]]
store i8 6, i8* @char
ret void
}
define i8 @global8_load() {
; CHECK-LABEL: global8_load:
; CHECK: lds r24, char
%result = load i8, i8* @char
ret i8 %result
}
define void @array8_store() {
; CHECK-LABEL: array8_store:
; CHECK: ldi [[REG1:r[0-9]+]], 1
; CHECK: sts char.array, [[REG1]]
; CHECK: ldi [[REG2:r[0-9]+]], 2
; CHECK: sts char.array+1, [[REG2]]
; CHECK: ldi [[REG:r[0-9]+]], 3
; CHECK: sts char.array+2, [[REG]]
store i8 1, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @char.array, i32 0, i64 0)
store i8 2, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @char.array, i32 0, i64 1)
store i8 3, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @char.array, i32 0, i64 2)
ret void
}
define i8 @array8_load() {
; CHECK-LABEL: array8_load:
; CHECK: lds r24, char.array+2
%result = load i8, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @char.array, i32 0, i64 2)
ret i8 %result
}
define i8 @static8_inc() {
; CHECK-LABEL: static8_inc:
; CHECK: lds r24, char.static
; CHECK: inc r24
; CHECK: sts char.static, r24
%1 = load i8, i8* @char.static
%inc = add nsw i8 %1, 1
store i8 %inc, i8* @char.static
ret i8 %inc
}
define void @global16_store() {
; CHECK-LABEL: global16_store:
; CHECK: ldi [[REG1:r[0-9]+]], 187
; CHECK: ldi [[REG2:r[0-9]+]], 170
; CHECK: sts int+1, [[REG2]]
; CHECK: sts int, [[REG1]]
store i16 43707, i16* @int
ret void
}
define i16 @global16_load() {
; CHECK-LABEL: global16_load:
; CHECK: lds r24, int
; CHECK: lds r25, int+1
%result = load i16, i16* @int
ret i16 %result
}
define void @array16_store() {
; CHECK-LABEL: array16_store:
; CHECK: ldi [[REG1:r[0-9]+]], 187
; CHECK: ldi [[REG2:r[0-9]+]], 170
; CHECK: sts int.array+1, [[REG2]]
; CHECK: sts int.array, [[REG1]]
; CHECK: ldi [[REG1:r[0-9]+]], 204
; CHECK: ldi [[REG2:r[0-9]+]], 170
; CHECK: sts int.array+3, [[REG2]]
; CHECK: sts int.array+2, [[REG1]]
; CHECK: ldi [[REG1:r[0-9]+]], 221
; CHECK: ldi [[REG2:r[0-9]+]], 170
; CHECK: sts int.array+5, [[REG2]]
; CHECK: sts int.array+4, [[REG1]]
store i16 43707, i16* getelementptr inbounds ([3 x i16], [3 x i16]* @int.array, i32 0, i64 0)
store i16 43724, i16* getelementptr inbounds ([3 x i16], [3 x i16]* @int.array, i32 0, i64 1)
store i16 43741, i16* getelementptr inbounds ([3 x i16], [3 x i16]* @int.array, i32 0, i64 2)
ret void
}
define i16 @array16_load() {
; CHECK-LABEL: array16_load:
; CHECK: lds r24, int.array+4
; CHECK: lds r25, int.array+5
%result = load i16, i16* getelementptr inbounds ([3 x i16], [3 x i16]* @int.array, i32 0, i64 2)
ret i16 %result
}
define i16 @static16_inc() {
; CHECK-LABEL: static16_inc:
; CHECK: lds r24, int.static
; CHECK: lds r25, int.static+1
; CHECK: adiw r24, 1
; CHECK: sts int.static+1, r25
; CHECK: sts int.static, r24
%1 = load i16, i16* @int.static
%inc = add nsw i16 %1, 1
store i16 %inc, i16* @int.static
ret i16 %inc
}
define void @global32_store() {
; CHECK-LABEL: global32_store:
; CHECK: ldi [[REG1:r[0-9]+]], 187
; CHECK: ldi [[REG2:r[0-9]+]], 170
; CHECK: sts long+3, [[REG2]]
; CHECK: sts long+2, [[REG1]]
; CHECK: ldi [[REG1:r[0-9]+]], 221
; CHECK: ldi [[REG2:r[0-9]+]], 204
; CHECK: sts long+1, [[REG2]]
; CHECK: sts long, [[REG1]]
store i32 2864434397, i32* @long
ret void
}
define i32 @global32_load() {
; CHECK-LABEL: global32_load:
; CHECK: lds r22, long
; CHECK: lds r23, long+1
; CHECK: lds r24, long+2
; CHECK: lds r25, long+3
%result = load i32, i32* @long
ret i32 %result
}
define void @array32_store() {
; CHECK-LABEL: array32_store:
; CHECK: ldi [[REG1:r[0-9]+]], 27
; CHECK: ldi [[REG2:r[0-9]+]], 172
; CHECK: sts long.array+3, [[REG2]]
; CHECK: sts long.array+2, [[REG1]]
; CHECK: ldi [[REG1:r[0-9]+]], 68
; CHECK: ldi [[REG2:r[0-9]+]], 13
; CHECK: sts long.array+1, [[REG2]]
; CHECK: sts long.array, [[REG1]]
; CHECK: ldi [[REG1:r[0-9]+]], 102
; CHECK: ldi [[REG2:r[0-9]+]], 85
; CHECK: sts long.array+7, [[REG2]]
; CHECK: sts long.array+6, [[REG1]]
; CHECK: ldi [[REG1:r[0-9]+]], 136
; CHECK: ldi [[REG2:r[0-9]+]], 119
; CHECK: sts long.array+5, [[REG2]]
; CHECK: sts long.array+4, [[REG1]]
; CHECK: ldi [[REG1:r[0-9]+]], 170
; CHECK: ldi [[REG2:r[0-9]+]], 153
; CHECK: sts long.array+11, [[REG2]]
; CHECK: sts long.array+10, [[REG1]]
; CHECK: ldi [[REG1:r[0-9]+]], 204
; CHECK: ldi [[REG2:r[0-9]+]], 187
; CHECK: sts long.array+9, [[REG2]]
; CHECK: sts long.array+8, [[REG1]]
store i32 2887454020, i32* getelementptr inbounds ([3 x i32], [3 x i32]* @long.array, i32 0, i64 0)
store i32 1432778632, i32* getelementptr inbounds ([3 x i32], [3 x i32]* @long.array, i32 0, i64 1)
store i32 2578103244, i32* getelementptr inbounds ([3 x i32], [3 x i32]* @long.array, i32 0, i64 2)
ret void
}
define i32 @array32_load() {
; CHECK-LABEL: array32_load:
; CHECK: lds r22, long.array+8
; CHECK: lds r23, long.array+9
; CHECK: lds r24, long.array+10
; CHECK: lds r25, long.array+11
%result = load i32, i32* getelementptr inbounds ([3 x i32], [3 x i32]* @long.array, i32 0, i64 2)
ret i32 %result
}
define i32 @static32_inc() {
; CHECK-LABEL: static32_inc:
; CHECK: lds r22, long.static
; CHECK: lds r23, long.static+1
; CHECK: lds r24, long.static+2
; CHECK: lds r25, long.static+3
; CHECK: subi r22, 255
; CHECK: sbci r23, 255
; CHECK: sbci r24, 255
; CHECK: sbci r25, 255
; CHECK: sts long.static+3, r25
; CHECK: sts long.static+2, r24
; CHECK: sts long.static+1, r23
; CHECK: sts long.static, r22
%1 = load i32, i32* @long.static
%inc = add nsw i32 %1, 1
store i32 %inc, i32* @long.static
ret i32 %inc
}
define void @global64_store() {
; CHECK-LABEL: global64_store:
; CHECK: ldi [[REG1:r[0-9]+]], 34
; CHECK: ldi [[REG2:r[0-9]+]], 17
; CHECK: sts longlong+7, [[REG2]]
; CHECK: sts longlong+6, [[REG1]]
; CHECK: ldi [[REG1:r[0-9]+]], 68
; CHECK: ldi [[REG2:r[0-9]+]], 51
; CHECK: sts longlong+5, [[REG2]]
; CHECK: sts longlong+4, [[REG1]]
; CHECK: ldi [[REG1:r[0-9]+]], 102
; CHECK: ldi [[REG2:r[0-9]+]], 85
; CHECK: sts longlong+3, [[REG2]]
; CHECK: sts longlong+2, [[REG1]]
; CHECK: ldi [[REG1:r[0-9]+]], 136
; CHECK: ldi [[REG2:r[0-9]+]], 119
; CHECK: sts longlong+1, [[REG2]]
; CHECK: sts longlong, [[REG1]]
store i64 1234605616436508552, i64* @longlong
ret void
}
define i64 @global64_load() {
; CHECK-LABEL: global64_load:
; CHECK: lds r18, longlong
; CHECK: lds r19, longlong+1
; CHECK: lds r20, longlong+2
; CHECK: lds r21, longlong+3
; CHECK: lds r22, longlong+4
; CHECK: lds r23, longlong+5
; CHECK: lds r24, longlong+6
; CHECK: lds r25, longlong+7
%result = load i64, i64* @longlong
ret i64 %result
}
define void @array64_store() {
; CHECK-LABEL: array64_store:
; CHECK: ldi [[REG1:r[0-9]+]], 34
; CHECK: ldi [[REG2:r[0-9]+]], 17
; CHECK: sts longlong.array+7, [[REG2]]
; CHECK: sts longlong.array+6, [[REG1]]
; CHECK: ldi [[REG1:r[0-9]+]], 68
; CHECK: ldi [[REG2:r[0-9]+]], 51
; CHECK: sts longlong.array+5, [[REG2]]
; CHECK: sts longlong.array+4, [[REG1]]
; CHECK: ldi [[REG1:r[0-9]+]], 102
; CHECK: ldi [[REG2:r[0-9]+]], 85
; CHECK: sts longlong.array+3, [[REG2]]
; CHECK: sts longlong.array+2, [[REG1]]
; CHECK: ldi [[REG1:r[0-9]+]], 136
; CHECK: ldi [[REG2:r[0-9]+]], 119
; CHECK: sts longlong.array+1, [[REG2]]
; CHECK: sts longlong.array, [[REG1]]
store i64 1234605616436508552, i64* getelementptr inbounds ([3 x i64], [3 x i64]* @longlong.array, i64 0, i64 0)
store i64 81985529216486895, i64* getelementptr inbounds ([3 x i64], [3 x i64]* @longlong.array, i64 0, i64 1)
store i64 1836475854449306472, i64* getelementptr inbounds ([3 x i64], [3 x i64]* @longlong.array, i64 0, i64 2)
ret void
}
define i64 @array64_load() {
; CHECK-LABEL: array64_load:
; CHECK: lds r18, longlong.array+16
; CHECK: lds r19, longlong.array+17
; CHECK: lds r20, longlong.array+18
; CHECK: lds r21, longlong.array+19
; CHECK: lds r22, longlong.array+20
; CHECK: lds r23, longlong.array+21
; CHECK: lds r24, longlong.array+22
; CHECK: lds r25, longlong.array+23
%result = load i64, i64* getelementptr inbounds ([3 x i64], [3 x i64]* @longlong.array, i64 0, i64 2)
ret i64 %result
}
define i64 @static64_inc() {
; CHECK-LABEL: static64_inc:
; CHECK: lds r18, longlong.static
; CHECK: lds r19, longlong.static+1
; CHECK: lds r20, longlong.static+2
; CHECK: lds r21, longlong.static+3
; CHECK: lds r22, longlong.static+4
; CHECK: lds r23, longlong.static+5
; CHECK: lds r24, longlong.static+6
; CHECK: lds r25, longlong.static+7
; CHECK: subi r18, 255
; CHECK: sbci r19, 255
; CHECK: sbci r20, 255
; CHECK: sbci r21, 255
; CHECK: sbci r22, 255
; CHECK: sbci r23, 255
; CHECK: sbci r24, 255
; CHECK: sbci r25, 255
; CHECK: sts longlong.static+7, r25
; CHECK: sts longlong.static+6, r24
; CHECK: sts longlong.static+5, r23
; CHECK: sts longlong.static+4, r22
; CHECK: sts longlong.static+3, r21
; CHECK: sts longlong.static+2, r20
; CHECK: sts longlong.static+1, r19
; CHECK: sts longlong.static, r18
%1 = load i64, i64* @longlong.static
%inc = add nsw i64 %1, 1
store i64 %inc, i64* @longlong.static
ret i64 %inc
}
define i8 @constantaddr_read8() {
; CHECK-LABEL: constantaddr_read8:
; CHECK: lds r24, 1234
%1 = load i8, i8* inttoptr (i16 1234 to i8*)
ret i8 %1
}
define i16 @constantaddr_read16() {
; CHECK-LABEL: constantaddr_read16:
; CHECK: lds r24, 1234
; CHECK: lds r25, 1235
%1 = load i16, i16* inttoptr (i16 1234 to i16*)
ret i16 %1
}
define void @constantaddr_write8() {
; CHECK-LABEL: constantaddr_write8:
; CHECK: sts 1234
store i8 22, i8* inttoptr (i16 1234 to i8*)
ret void
}
define void @constantaddr_write16() {
; CHECK-LABEL: constantaddr_write16:
; CHECK: sts 1235
; CHECK: sts 1234
store i16 2222, i16* inttoptr (i16 1234 to i16*)
ret void
}

View File

@ -0,0 +1,78 @@
; RUN: llc < %s -march=avr | FileCheck %s
declare void @foo(i16*, i16*, i8*)
define void @test1(i16 %x) {
; CHECK-LABEL: test1:
; CHECK: out 61, r28
; SP copy
; CHECK-NEXT: in [[SPCOPY1:r[0-9]+]], 61
; CHECK-NEXT: in [[SPCOPY2:r[0-9]+]], 62
; allocate first dynalloca
; CHECK: in {{.*}}, 61
; CHECK: in {{.*}}, 62
; CHECK: sub
; CHECK: sbc
; CHECK: in r0, 63
; CHECK-NEXT: cli
; CHECK-NEXT: out 62, {{.*}}
; CHECK-NEXT: out 63, r0
; CHECK-NEXT: out 61, {{.*}}
; Test writes
; CHECK: std Z+12, {{.*}}
; CHECK: std Z+13, {{.*}}
; CHECK: std Z+7, {{.*}}
; CHECK-NOT: std
; Test SP restore
; CHECK: in r0, 63
; CHECK-NEXT: cli
; CHECK-NEXT: out 62, [[SPCOPY2]]
; CHECK-NEXT: out 63, r0
; CHECK-NEXT: out 61, [[SPCOPY1]]
%a = alloca [8 x i16]
%vla = alloca i16, i16 %x
%add = shl nsw i16 %x, 1
%vla1 = alloca i8, i16 %add
%arrayidx = getelementptr inbounds [8 x i16], [8 x i16]* %a, i16 0, i16 2
store i16 3, i16* %arrayidx
%arrayidx2 = getelementptr inbounds i16, i16* %vla, i16 6
store i16 4, i16* %arrayidx2
%arrayidx3 = getelementptr inbounds i8, i8* %vla1, i16 7
store i8 44, i8* %arrayidx3
%arraydecay = getelementptr inbounds [8 x i16], [8 x i16]* %a, i16 0, i16 0
call void @foo(i16* %arraydecay, i16* %vla, i8* %vla1)
ret void
}
declare void @foo2(i16*, i64, i64, i64)
; Test that arguments are passed through pushes into the call instead of
; allocating the call frame space in the prologue. Also test that SP is restored
; after the call frame is restored and not before.
define void @dynalloca2(i16 %x) {
; CHECK-LABEL: dynalloca2:
; CHECK: in [[SPCOPY1:r[0-9]+]], 61
; CHECK: in [[SPCOPY2:r[0-9]+]], 62
; CHECK: push
; CHECK-NOT: st
; CHECK-NOT: std
; CHECK: call
; Call frame restore
; CHECK-NEXT: in r30, 61
; CHECK-NEXT: in r31, 62
; CHECK-NEXT: adiw r30, 8
; CHECK-NEXT: in r0, 63
; CHECK-NEXT: cli
; CHECK-NEXT: out 62, r31
; CHECK-NEXT: out 63, r0
; CHECK-NEXT: out 61, r30
; SP restore
; CHECK: in r0, 63
; CHECK-NEXT: cli
; CHECK-NEXT: out 62, r29
; CHECK-NEXT: out 63, r0
; CHECK-NEXT: out 61, r28
%vla = alloca i16, i16 %x
call void @foo2(i16* %vla, i64 0, i64 0, i64 0)
ret void
}

92
test/CodeGen/AVR/eor.ll Normal file
View File

@ -0,0 +1,92 @@
; RUN: llc < %s -march=avr | FileCheck %s
; Tests for the exclusive OR operation.
define i8 @eor8_reg_reg(i8 %a, i8 %b) {
; CHECK-LABEL: eor8_reg_reg:
; CHECK: eor r24, r22
%result = xor i8 %a, %b
ret i8 %result
}
define i8 @eor8_reg_imm(i8 %a) {
; CHECK-LABEL: eor8_reg_imm:
; CHECK: ldi r25, 5
; CHECK: eor r24, r25
%result = xor i8 %a, 5
ret i8 %result
}
define i16 @eor16_reg_reg(i16 %a, i16 %b) {
; CHECK-LABEL: eor16_reg_reg:
; CHECK: eor r24, r22
; CHECK: eor r25, r23
%result = xor i16 %a, %b
ret i16 %result
}
define i16 @eor16_reg_imm(i16 %a) {
; CHECK-LABEL: eor16_reg_imm:
; CHECK: ldi r18, 210
; CHECK: ldi r19, 4
; CHECK: eor r24, r18
; CHECK: eor r25, r19
%result = xor i16 %a, 1234
ret i16 %result
}
define i32 @eor32_reg_reg(i32 %a, i32 %b) {
; CHECK-LABEL: eor32_reg_reg:
; CHECK: eor r22, r18
; CHECK: eor r23, r19
; CHECK: eor r24, r20
; CHECK: eor r25, r21
%result = xor i32 %a, %b
ret i32 %result
}
define i32 @eor32_reg_imm(i32 %a) {
; CHECK-LABEL: eor32_reg_imm:
; CHECK: ldi r18, 210
; CHECK: ldi r19, 4
; CHECK: eor r22, r18
; CHECK: eor r23, r19
%result = xor i32 %a, 1234
ret i32 %result
}
define i64 @eor64_reg_reg(i64 %a, i64 %b) {
; CHECK-LABEL: eor64_reg_reg:
; CHECK: eor r18, r10
; CHECK: eor r19, r11
; CHECK: eor r20, r12
; CHECK: eor r21, r13
; CHECK: eor r22, r14
; CHECK: eor r23, r15
; CHECK: eor r24, r16
; CHECK: eor r25, r17
%result = xor i64 %a, %b
ret i64 %result
}
define i64 @eor64_reg_imm(i64 %a) {
; CHECK-LABEL: eor64_reg_imm:
; CHECK: ldi r30, 253
; CHECK: ldi r31, 255
; CHECK: eor r18, r30
; CHECK: eor r19, r31
; CHECK: ldi r30, 155
; CHECK: ldi r31, 88
; CHECK: eor r20, r30
; CHECK: eor r21, r31
; CHECK: ldi r30, 76
; CHECK: ldi r31, 73
; CHECK: eor r22, r30
; CHECK: eor r23, r31
; CHECK: ldi r30, 31
; CHECK: ldi r31, 242
; CHECK: eor r24, r30
; CHECK: eor r25, r31
%result = xor i64 %a, 17446744073709551613
ret i64 %result
}

View File

@ -0,0 +1,56 @@
; RUN: llc < %s -march=avr | FileCheck %s
; XFAIL: *
; This occurs when compiling Rust libcore.
;
; Assertion failed:
; (DstReg != SrcReg && "SrcReg and DstReg cannot be the same")
; lib/Target/AVR/AVRExpandPseudoInsts.cpp, line 817
;
; https://github.com/avr-llvm/llvm/issues/229
; CHECK-LABEL: rust_eh_personality
declare void @rust_eh_personality()
; CHECK-LABEL: __udivmoddi4
define void @__udivmoddi4(i64 %arg, i64 %arg1) personality i32 (...)* bitcast (void ()* @rust_eh_personality to i32 (...)*) {
entry-block:
%tmp = lshr i64 %arg, 32
%tmp2 = trunc i64 %tmp to i32
%tmp3 = trunc i64 %arg to i32
%tmp4 = add i64 %arg1, -1
br label %bb135
bb133.loopexit:
ret void
bb135:
%carry.0120 = phi i64 [ 0, %entry-block ], [ %phitmp, %bb135 ]
%q.sroa.12.1119 = phi i32 [ %tmp3, %entry-block ], [ %q.sroa.12.0.extract.trunc, %bb135 ]
%q.sroa.0.1118 = phi i32 [ 0, %entry-block ], [ %q.sroa.0.0.extract.trunc, %bb135 ]
%r.sroa.0.1116 = phi i32 [ %tmp2, %entry-block ], [ undef, %bb135 ]
%r.sroa.0.0.insert.ext62 = zext i32 %r.sroa.0.1116 to i64
%r.sroa.0.0.insert.insert64 = or i64 0, %r.sroa.0.0.insert.ext62
%tmp5 = shl nuw nsw i64 %r.sroa.0.0.insert.ext62, 1
%q.sroa.12.0.insert.ext101 = zext i32 %q.sroa.12.1119 to i64
%q.sroa.12.0.insert.shift102 = shl nuw i64 %q.sroa.12.0.insert.ext101, 32
%q.sroa.0.0.insert.ext87 = zext i32 %q.sroa.0.1118 to i64
%q.sroa.0.0.insert.insert89 = or i64 %q.sroa.12.0.insert.shift102, %q.sroa.0.0.insert.ext87
%tmp6 = lshr i64 %q.sroa.12.0.insert.ext101, 31
%tmp7 = lshr i64 %r.sroa.0.0.insert.insert64, 31
%tmp8 = shl nuw nsw i64 %q.sroa.0.0.insert.ext87, 1
%tmp9 = or i64 %tmp8, %carry.0120
%q.sroa.0.0.extract.trunc = trunc i64 %tmp9 to i32
%tmp10 = lshr i64 %q.sroa.0.0.insert.insert89, 31
%q.sroa.12.0.extract.trunc = trunc i64 %tmp10 to i32
%r.sroa.13.0.insert.shift72 = shl i64 %tmp7, 32
%.masked114 = and i64 %tmp5, 4294967294
%r.sroa.0.0.insert.ext57 = or i64 %tmp6, %.masked114
%r.sroa.0.0.insert.insert59 = or i64 %r.sroa.0.0.insert.ext57, %r.sroa.13.0.insert.shift72
%tmp11 = sub i64 %tmp4, %r.sroa.0.0.insert.insert59
%tmp12 = ashr i64 %tmp11, 63
%phitmp = and i64 %tmp12, 1
%tmp13 = icmp ult i32 undef, 32
br i1 %tmp13, label %bb135, label %bb133.loopexit
}

View File

@ -0,0 +1,23 @@
; RUN: llc < %s -march=avr | FileCheck %s
; XFAIL: *
; Causes an assertion error
; Assertion failed: (Lo.getValueType() == TLI.getTypeToTransformTo(*DAG.getContext(), Op.getValueType()) &&
; Hi.getValueType() == Lo.getValueType() &&
; "Invalid type for expanded integer"),
; function SetExpandedInteger
; file lib/CodeGen/SelectionDAG/LegalizeTypes.cpp
; CHECK-LABEL: foo
define void @foo(i16 %a) {
ifcont:
%cmp_result = icmp eq i16 %a, 255
%bool_result = uitofp i1 %cmp_result to double
%result = fcmp one double 0.000000e+00, %bool_result
br i1 %result, label %then, label %else
then:
ret void
else:
ret void
}

65
test/CodeGen/AVR/frame.ll Normal file
View File

@ -0,0 +1,65 @@
; RUN: llc -mattr=mul < %s -march=avr | FileCheck %s
declare float @dsin(float)
declare float @dcos(float)
declare float @dasin(float)
; Test prologue and epilogue insertion
define float @f3(float %days) {
entry:
; CHECK-LABEL: f3:
; prologue code:
; CHECK: push r28
; CHECK: push r29
; CHECK: in r28, 61
; CHECK-NEXT: in r29, 62
; CHECK-NEXT: sbiw r28, [[SIZE:[0-9]+]]
; CHECK-NEXT: in r0, 63
; CHECK-NEXT: cli
; CHECK-NEXT: out 62, r29
; CHECK-NEXT: out 63, r0
; CHECK-NEXT: out 61, r28
; epilogue code:
; CHECK: adiw r28, [[SIZE]]
; CHECK-NEXT: in r0, 63
; CHECK-NEXT: cli
; CHECK-NEXT: out 62, r29
; CHECK-NEXT: out 63, r0
; CHECK-NEXT: out 61, r28
; CHECK: pop r29
; CHECK: pop r28
%mul = fmul float %days, 0x3FEF8A6C60000000
%add = fadd float %mul, 0x40718776A0000000
%mul1 = fmul float %days, 0x3FEF8A09A0000000
%add2 = fadd float %mul1, 0x4076587740000000
%mul3 = fmul float %days, 0x3E81B35CC0000000
%sub = fsub float 0x3FFEA235C0000000, %mul3
%call = call float @dsin(float %add2)
%mul4 = fmul float %sub, %call
%mul5 = fmul float %days, 0x3E27C04CA0000000
%sub6 = fsub float 0x3F94790B80000000, %mul5
%mul7 = fmul float %add2, 2.000000e+00
%call8 = call float @dsin(float %mul7)
%mul9 = fmul float %sub6, %call8
%add10 = fadd float %mul4, %mul9
%add11 = fadd float %add, %add10
%mul12 = fmul float %days, 0x3E13C5B640000000
%sub13 = fsub float 0x3F911C1180000000, %mul12
%mul14 = fmul float %add, 2.000000e+00
%call15 = call float @dsin(float %mul14)
%mul16 = fmul float %call15, 0x3FF1F736C0000000
%mul17 = fmul float %sub13, 2.000000e+00
%mul19 = fmul float %mul17, %call
%sub20 = fsub float %mul16, %mul19
%mul21 = fmul float %sub13, 4.000000e+00
%mul22 = fmul float %mul21, 0x3FF1F736C0000000
%mul24 = fmul float %mul22, %call
%call26 = call float @dcos(float %mul14)
%mul27 = fmul float %mul24, %call26
%add28 = fadd float %sub20, %mul27
%call29 = call float @dsin(float %add11)
%mul30 = fmul float %call29, 0x3FF0AB6960000000
%call31 = call float @dasin(float %mul30)
%add32 = fadd float %call31, %add28
ret float %add32
}

View File

@ -1,4 +1,5 @@
; RUN: llc < %s -march=avr | FileCheck %s
; XFAIL: *
; This tests how LLVM handles IR which puts very high
; presure on the PTRREGS class for the register allocator.

View File

@ -0,0 +1,337 @@
; RUN: llc < %s -march=avr | FileCheck %s
; XFAIL: *
;CHECK-LABEL: no_operands:
define void @no_operands() {
;CHECK: add r24, r22
call void asm sideeffect "add r24, r22", ""() nounwind
ret void
}
;CHECK-LABEL: input_operand:
define void @input_operand(i8 %a) {
;CHECK: add r24, r24
call void asm sideeffect "add $0, $0", "r"(i8 %a) nounwind
ret void
}
;CHECK-LABEL: simple_upper_regs:
define void @simple_upper_regs(i8 %p0, i8 %p1, i8 %p2, i8 %p3,
i8 %p4, i8 %p5, i8 %p6, i8 %p7) {
;CHECK: some_instr r17, r22, r20, r18, r16, r19, r21, r23
call void asm sideeffect "some_instr $0, $1, $2, $3, $4, $5, $6, $7",
"a,a,a,a,a,a,a,a" (i8 %p0, i8 %p1, i8 %p2, i8 %p3,
i8 %p4, i8 %p5, i8 %p6, i8 %p7) nounwind
ret void
}
;CHECK-LABEL: upper_regs:
define void @upper_regs(i8 %p0) {
;CHECK: some_instr r24
call void asm sideeffect "some_instr $0", "d" (i8 %p0) nounwind
ret void
}
;CHECK-LABEL: lower_regs:
define void @lower_regs(i8 %p0) {
;CHECK: some_instr r15
call void asm sideeffect "some_instr $0", "l" (i8 %p0) nounwind
ret void
}
;CHECK-LABEL: special_upper_regs:
define void @special_upper_regs(i8 %p0, i8 %p1, i8 %p2, i8 %p3) {
;CHECK: some_instr r24,r28,r26,r30
call void asm sideeffect "some_instr $0,$1,$2,$3", "w,w,w,w" (i8 %p0, i8 %p1, i8 %p2, i8 %p3) nounwind
ret void
}
;CHECK-LABEL: xyz_reg:
define void @xyz_reg(i16 %var) {
;CHECK: some_instr r26, r28, r30
call void asm sideeffect "some_instr $0, $1, $2", "x,y,z" (i16 %var, i16 %var, i16 %var) nounwind
ret void
}
;TODO
; How to use SP reg properly in inline asm??
; define void @sp_reg(i16 %var)
;CHECK-LABEL: ptr_reg:
define void @ptr_reg(i16 %var0, i16 %var1, i16 %var2) {
;CHECK: some_instr r28, r26, r30
call void asm sideeffect "some_instr $0, $1, $2", "e,e,e" (i16 %var0, i16 %var1, i16 %var2) nounwind
ret void
}
;CHECK-LABEL: base_ptr_reg:
define void @base_ptr_reg(i16 %var0, i16 %var1) {
;CHECK: some_instr r28, r30
call void asm sideeffect "some_instr $0, $1", "b,b" (i16 %var0, i16 %var1) nounwind
ret void
}
;CHECK-LABEL: input_output_operand:
define i8 @input_output_operand(i8 %a, i8 %b) {
;CHECK: add r24, r24
%1 = call i8 asm "add $0, $1", "=r,r"(i8 %a) nounwind
ret i8 %1
}
;CHECK-LABEL: temp_reg:
define void @temp_reg(i8 %a) {
;CHECK: some_instr r0
call void asm sideeffect "some_instr $0", "t" (i8 %a) nounwind
ret void
}
;CHECK-LABEL: int_0_63:
define void @int_0_63() {
;CHECK: some_instr 5
call void asm sideeffect "some_instr $0", "I" (i8 5) nounwind
ret void
}
;CHECK-LABEL: int_minus63_0:
define void @int_minus63_0() {
;CHECK: some_instr -5
call void asm sideeffect "some_instr $0", "J" (i8 -5) nounwind
ret void
}
;CHECK-LABEL: int_2_2:
define void @int_2_2() {
;CHECK: some_instr 2
call void asm sideeffect "some_instr $0", "K" (i8 2) nounwind
ret void
}
;CHECK-LABEL: int_0_0:
define void @int_0_0() {
;CHECK: some_instr 0
call void asm sideeffect "some_instr $0", "L" (i8 0) nounwind
ret void
}
;CHECK-LABEL: int_0_255:
define void @int_0_255() {
;CHECK: some_instr 254
call void asm sideeffect "some_instr $0", "M" (i8 254) nounwind
ret void
}
;CHECK-LABEL: int_minus1_minus1:
define void @int_minus1_minus1() {
;CHECK: some_instr -1
call void asm sideeffect "some_instr $0", "N" (i8 -1) nounwind
ret void
}
;CHECK-LABEL: int_8_or_16_or_24:
define void @int_8_or_16_or_24() {
;CHECK: some_instr 8, 16, 24
call void asm sideeffect "some_instr $0, $1, $2", "O,O,O" (i8 8, i8 16, i8 24) nounwind
ret void
}
;CHECK-LABEL: int_1_1:
define void @int_1_1() {
;CHECK: some_instr 1
call void asm sideeffect "some_instr $0", "P" (i8 1) nounwind
ret void
}
;CHECK-LABEL: int_minus6_5:
define void @int_minus6_5() {
;CHECK: some_instr -6
call void asm sideeffect "some_instr $0", "R" (i8 -6) nounwind
ret void
}
;CHECK-LABEL: float_0_0:
define void @float_0_0() {
;CHECK: some_instr 0
call void asm sideeffect "some_instr $0", "G" (float 0.0) nounwind
ret void
}
; Memory constraint
@a = internal global i16 0, align 4
@b = internal global i16 0, align 4
; CHECK-LABEL: mem_global:
define void @mem_global() {
;CHECK: some_instr Y, Z
call void asm "some_instr $0, $1", "=*Q,=*Q"(i16* @a, i16* @b)
ret void
}
; CHECK-LABEL: mem_params:
define void @mem_params(i16* %a, i16* %b) {
;CHECK: some_instr Y, Z
call void asm "some_instr $0, $1", "=*Q,=*Q"(i16* %a, i16* %b)
ret void
}
; CHECK-LABEL: mem_local:
define void @mem_local() {
%a = alloca i16
%b = alloca i16
;CHECK: some_instr Y+3, Y+1
call void asm "some_instr $0, $1", "=*Q,=*Q"(i16* %a, i16* %b)
ret void
}
; CHECK-LABEL: mem_mixed:
define void @mem_mixed() {
%a = alloca i16
%b = alloca i16
;CHECK: some_instr Z, Y+3, Y+1
call void asm "some_instr $0, $1, $2", "=*Q,=*Q,=*Q"(i16* @a, i16* %a, i16* %b)
ret void
}
; CHECK-LABEL: mem_gep:
define i8 @mem_gep(i8* %p) {
entry:
; CHECK: movw r30, r24
%arrayidx = getelementptr inbounds i8, i8* %p, i16 1
; CHECK: ld r24, Z+1
%0 = tail call i8 asm sideeffect "ld $0, $1\0A\09", "=r,*Q"(i8* %arrayidx)
ret i8 %0
}
; Multibyte references
; CHECK-LABEL: multibyte_i16
define void @multibyte_i16(i16 %a) {
entry:
; CHECK: instr r24 r25
call void asm sideeffect "instr ${0:A} ${0:B}", "r"(i16 %a)
; CHECK: instr r25 r24
call void asm sideeffect "instr ${0:B} ${0:A}", "r"(i16 %a)
ret void
}
; CHECK-LABEL: multibyte_i32
define void @multibyte_i32(i32 %a) {
entry:
; CHECK: instr r22 r23 r24 r25
call void asm sideeffect "instr ${0:A} ${0:B} ${0:C} ${0:D}", "r"(i32 %a)
; CHECK: instr r25 r24 r23 r22
call void asm sideeffect "instr ${0:D} ${0:C} ${0:B} ${0:A}", "r"(i32 %a)
ret void
}
; CHECK-LABEL: multibyte_alternative_name
define void @multibyte_alternative_name(i16* %p) {
entry:
; CHECK: instr Z
call void asm sideeffect "instr ${0:a}", "e" (i16* %p)
ret void
}
; CHECK-LABEL: multibyte_a_i32
define void @multibyte_a_i32() {
entry:
%a = alloca i32
%0 = load i32, i32* %a
; CHECK: instr r20 r21 r22 r23
call void asm sideeffect "instr ${0:A} ${0:B} ${0:C} ${0:D}", "a"(i32 %0)
ret void
}
@c = internal global i32 0
; CHECK-LABEL: multibyte_b_i32
define void @multibyte_b_i32() {
entry:
%0 = load i32, i32* @c
; CHECK: instr r28 r29 r30 r31
call void asm sideeffect "instr ${0:A} ${0:B} ${0:C} ${0:D}", "b"(i32 %0)
ret void
}
; CHECK-LABEL: multibyte_d_i32
define void @multibyte_d_i32() {
entry:
%a = alloca i32
%0 = load i32, i32* %a
; CHECK: instr r18 r19 r24 r25
call void asm sideeffect "instr ${0:A} ${0:B} ${0:C} ${0:D}", "d"(i32 %0)
ret void
}
; CHECK-LABEL: multibyte_e_i32
define void @multibyte_e_i32() {
entry:
%a = alloca i32
%0 = load i32, i32* %a
; CHECK: instr r26 r27 r30 r31
call void asm sideeffect "instr ${0:A} ${0:B} ${0:C} ${0:D}", "e"(i32 %0)
ret void
}
; CHECK-LABEL: multibyte_l_i32
define void @multibyte_l_i32() {
entry:
%a = alloca i32
%0 = load i32, i32* %a
; CHECK: instr r12 r13 r14 r15
call void asm sideeffect "instr ${0:A} ${0:B} ${0:C} ${0:D}", "l"(i32 %0)
ret void
}
; CHECK-LABEL: multibyte_a_i16
define void @multibyte_a_i16() {
entry:
%a = alloca i16
%0 = load i16, i16* %a
; CHECK: instr r22 r23
call void asm sideeffect "instr ${0:A} ${0:B}", "a"(i16 %0)
ret void
}
; CHECK-LABEL: multibyte_b_i16
define void @multibyte_b_i16() {
entry:
%a = alloca i16
%0 = load i16, i16* %a
; CHECK: instr r30 r31
call void asm sideeffect "instr ${0:A} ${0:B}", "b"(i16 %0)
ret void
}
; CHECK-LABEL: multibyte_d_i16
define void @multibyte_d_i16() {
entry:
%a = alloca i16
%0 = load i16, i16* %a
; CHECK: instr r24 r25
call void asm sideeffect "instr ${0:A} ${0:B}", "d"(i16 %0)
ret void
}
; CHECK-LABEL: multibyte_e_i16
define void @multibyte_e_i16() {
entry:
%a = alloca i16
%0 = load i16, i16* %a
; CHECK: instr r30 r31
call void asm sideeffect "instr ${0:A} ${0:B}", "e"(i16 %0)
ret void
}
; CHECK-LABEL: multibyte_l_i16
define void @multibyte_l_i16() {
entry:
%a = alloca i16
%0 = load i16, i16* %a
; CHECK: instr r14 r15
call void asm sideeffect "instr ${0:A} ${0:B}", "l"(i16 %0)
ret void
}

View File

@ -0,0 +1,33 @@
; RUN: llc < %s -march=avr | FileCheck %s
define avr_intrcc void @interrupt_handler() {
; CHECK-LABEL: interrupt_handler:
; CHECK: sei
; CHECK-NEXT: push r0
; CHECK-NEXT: push r1
; CHECK-NEXT: in r0, 63
; CHECK-NEXT: push r0
; CHECK: eor r0, r0
; CHECK: pop r0
; CHECK-NEXT: out 63, r0
; CHECK-NEXT: pop r1
; CHECK-NEXT: pop r0
; CHECK-NEXT: reti
ret void
}
define avr_signalcc void @signal_handler() {
; CHECK-LABEL: signal_handler:
; CHECK-NOT: sei
; CHECK: push r0
; CHECK-NEXT: push r1
; CHECK-NEXT: in r0, 63
; CHECK-NEXT: push r0
; CHECK: eor r0, r0
; CHECK: pop r0
; CHECK-NEXT: out 63, r0
; CHECK-NEXT: pop r1
; CHECK-NEXT: pop r0
; CHECK-NEXT: reti
ret void
}

97
test/CodeGen/AVR/io.ll Normal file
View File

@ -0,0 +1,97 @@
; RUN: llc < %s -march=avr | FileCheck %s
define i8 @read8() {
; CHECK-LABEL: read8
; CHECK: in r24, 8
%1 = load i8, i8* inttoptr (i16 40 to i8*)
ret i8 %1
}
define i16 @read16() {
; CHECK-LABEL: read16
; CHECK: in r24, 8
; CHECK: in r25, 9
%1 = load i16, i16* inttoptr (i16 40 to i16*)
ret i16 %1
}
define i32 @read32() {
; CHECK-LABEL: read32
; CHECK: in r22, 8
; CHECK: in r23, 9
; CHECK: in r24, 10
; CHECK: in r25, 11
%1 = load i32, i32* inttoptr (i16 40 to i32*)
ret i32 %1
}
define i64 @read64() {
; CHECK-LABEL: read64
; CHECK: in r18, 8
; CHECK: in r19, 9
; CHECK: in r20, 10
; CHECK: in r21, 11
; CHECK: in r22, 12
; CHECK: in r23, 13
; CHECK: in r24, 14
; CHECK: in r25, 15
%1 = load i64, i64* inttoptr (i16 40 to i64*)
ret i64 %1
}
define void @write8() {
; CHECK-LABEL: write8
; CHECK: out 8
store i8 22, i8* inttoptr (i16 40 to i8*)
ret void
}
define void @write16() {
; CHECK-LABEL: write16
; CHECK: out 9
; CHECK: out 8
store i16 1234, i16* inttoptr (i16 40 to i16*)
ret void
}
define void @write32() {
; CHECK-LABEL: write32
; CHECK: out 11
; CHECK: out 10
; CHECK: out 9
; CHECK: out 8
store i32 12345678, i32* inttoptr (i16 40 to i32*)
ret void
}
define void @write64() {
; CHECK-LABEL: write64
; CHECK: out 15
; CHECK: out 14
; CHECK: out 13
; CHECK: out 12
; CHECK: out 11
; CHECK: out 10
; CHECK: out 9
; CHECK: out 8
store i64 1234567891234567, i64* inttoptr (i16 40 to i64*)
ret void
}
define void @sbi8() {
; CHECK-LABEL: sbi8
; CHECK: sbi 8, 5
%1 = load i8, i8* inttoptr (i16 40 to i8*)
%or = or i8 %1, 32
store i8 %or, i8* inttoptr (i16 40 to i8*)
ret void
}
define void @cbi8() {
; CHECK-LABEL: cbi8
; CHECK: cbi 8, 5
%1 = load volatile i8, i8* inttoptr (i16 40 to i8*)
%and = and i8 %1, -33
store volatile i8 %and, i8* inttoptr (i16 40 to i8*)
ret void
}

View File

@ -1,3 +1,27 @@
if not 'AVR' in config.root.targets:
config.unsupported = True
config.suffixes = ['.ll', '.cpp']
import os, lit.TestRunner
from lit.formats import ShTest
targets = set(config.root.targets_to_build.split())
if not 'AVR' in targets:
config.unsupported = True
if 'AVRLIT_PORT' in os.environ:
config.environment['AVRLIT_PORT'] = os.environ['AVRLIT_PORT']
class AVRCodeGenTest(ShTest):
def __init__(self):
ShTest.__init__(self)
def execute(self, test, litConfig):
if test.getSourcePath().endswith('.cpp') and not 'AVRLIT_PORT' in os.environ:
return (lit.Test.UNSUPPORTED, 'AVRLIT_PORT environment variable is not set')
return ShTest.execute(self, test, litConfig)
config.test_format = AVRCodeGenTest()

142
test/CodeGen/AVR/load.ll Normal file
View File

@ -0,0 +1,142 @@
; RUN: llc -mattr=avr6,sram < %s -march=avr | FileCheck %s
define i8 @load8(i8* %x) {
; CHECK-LABEL: load8:
; CHECK: ld r24, {{[XYZ]}}
%1 = load i8, i8* %x
ret i8 %1
}
define i16 @load16(i16* %x) {
; CHECK-LABEL: load16:
; CHECK: ld r24, {{[YZ]}}
; CHECK: ldd r25, {{[YZ]}}+1
%1 = load i16, i16* %x
ret i16 %1
}
define i8 @load8disp(i8* %x) {
; CHECK-LABEL: load8disp:
; CHECK: ldd r24, {{[YZ]}}+63
%1 = getelementptr inbounds i8, i8* %x, i64 63
%2 = load i8, i8* %1
ret i8 %2
}
define i8 @load8nodisp(i8* %x) {
; CHECK-LABEL: load8nodisp:
; CHECK: movw r26, r24
; CHECK: subi r26, 192
; CHECK: sbci r27, 255
; CHECK: ld r24, {{[XYZ]}}
%1 = getelementptr inbounds i8, i8* %x, i64 64
%2 = load i8, i8* %1
ret i8 %2
}
define i16 @load16disp(i16* %x) {
; CHECK-LABEL: load16disp:
; CHECK: ldd r24, {{[YZ]}}+62
; CHECK: ldd r25, {{[YZ]}}+63
%1 = getelementptr inbounds i16, i16* %x, i64 31
%2 = load i16, i16* %1
ret i16 %2
}
define i16 @load16nodisp(i16* %x) {
; CHECK-LABEL: load16nodisp:
; CHECK: movw r30, r24
; CHECK: subi r30, 192
; CHECK: sbci r31, 255
; CHECK: ld r24, {{[YZ]}}
; CHECK: ldd r25, {{[YZ]}}+1
%1 = getelementptr inbounds i16, i16* %x, i64 32
%2 = load i16, i16* %1
ret i16 %2
}
define i8 @load8postinc(i8* %x, i8 %y) {
; CHECK-LABEL: load8postinc:
; CHECK: ld {{.*}}, {{[XYZ]}}+
entry:
%tobool6 = icmp eq i8 %y, 0
br i1 %tobool6, label %while.end, label %while.body
while.body: ; preds = %entry, %while.body
%r.09 = phi i8 [ %add, %while.body ], [ 0, %entry ]
%y.addr.08 = phi i8 [ %dec, %while.body ], [ %y, %entry ]
%x.addr.07 = phi i8* [ %incdec.ptr, %while.body ], [ %x, %entry ]
%dec = add i8 %y.addr.08, -1
%incdec.ptr = getelementptr inbounds i8, i8* %x.addr.07, i16 1
%0 = load i8, i8* %x.addr.07
%add = add i8 %0, %r.09
%tobool = icmp eq i8 %dec, 0
br i1 %tobool, label %while.end, label %while.body
while.end: ; preds = %while.body, %entry
%r.0.lcssa = phi i8 [ 0, %entry ], [ %add, %while.body ]
ret i8 %r.0.lcssa
}
define i16 @load16postinc(i16* %x, i16 %y) {
; CHECK-LABEL: load16postinc:
; CHECK: ld {{.*}}, {{[XYZ]}}+
; CHECK: ld {{.*}}, {{[XYZ]}}+
entry:
%tobool2 = icmp eq i16 %y, 0
br i1 %tobool2, label %while.end, label %while.body
while.body: ; preds = %entry, %while.body
%r.05 = phi i16 [ %add, %while.body ], [ 0, %entry ]
%y.addr.04 = phi i16 [ %dec, %while.body ], [ %y, %entry ]
%x.addr.03 = phi i16* [ %incdec.ptr, %while.body ], [ %x, %entry ]
%dec = add nsw i16 %y.addr.04, -1
%incdec.ptr = getelementptr inbounds i16, i16* %x.addr.03, i16 1
%0 = load i16, i16* %x.addr.03
%add = add nsw i16 %0, %r.05
%tobool = icmp eq i16 %dec, 0
br i1 %tobool, label %while.end, label %while.body
while.end: ; preds = %while.body, %entry
%r.0.lcssa = phi i16 [ 0, %entry ], [ %add, %while.body ]
ret i16 %r.0.lcssa
}
define i8 @load8predec(i8* %x, i8 %y) {
; CHECK-LABEL: load8predec:
; CHECK: ld {{.*}}, -{{[XYZ]}}
entry:
%tobool6 = icmp eq i8 %y, 0
br i1 %tobool6, label %while.end, label %while.body
while.body: ; preds = %entry, %while.body
%r.09 = phi i8 [ %add, %while.body ], [ 0, %entry ]
%y.addr.08 = phi i8 [ %dec, %while.body ], [ %y, %entry ]
%x.addr.07 = phi i8* [ %incdec.ptr, %while.body ], [ %x, %entry ]
%dec = add i8 %y.addr.08, -1
%incdec.ptr = getelementptr inbounds i8, i8* %x.addr.07, i16 -1
%0 = load i8, i8* %incdec.ptr
%add = add i8 %0, %r.09
%tobool = icmp eq i8 %dec, 0
br i1 %tobool, label %while.end, label %while.body
while.end: ; preds = %while.body, %entry
%r.0.lcssa = phi i8 [ 0, %entry ], [ %add, %while.body ]
ret i8 %r.0.lcssa
}
define i16 @load16predec(i16* %x, i16 %y) {
; CHECK-LABEL: load16predec:
; CHECK: ld {{.*}}, -{{[XYZ]}}
; CHECK: ld {{.*}}, -{{[XYZ]}}
entry:
%tobool2 = icmp eq i16 %y, 0
br i1 %tobool2, label %while.end, label %while.body
while.body: ; preds = %entry, %while.body
%r.05 = phi i16 [ %add, %while.body ], [ 0, %entry ]
%y.addr.04 = phi i16 [ %dec, %while.body ], [ %y, %entry ]
%x.addr.03 = phi i16* [ %incdec.ptr, %while.body ], [ %x, %entry ]
%dec = add nsw i16 %y.addr.04, -1
%incdec.ptr = getelementptr inbounds i16, i16* %x.addr.03, i16 -1
%0 = load i16, i16* %incdec.ptr
%add = add nsw i16 %0, %r.05
%tobool = icmp eq i16 %dec, 0
br i1 %tobool, label %while.end, label %while.body
while.end: ; preds = %while.body, %entry
%r.0.lcssa = phi i16 [ 0, %entry ], [ %add, %while.body ]
ret i16 %r.0.lcssa
}

80
test/CodeGen/AVR/or.ll Normal file
View File

@ -0,0 +1,80 @@
; RUN: llc < %s -march=avr | FileCheck %s
define i8 @or8_reg_reg(i8 %a, i8 %b) {
; CHECK-LABEL: or8_reg_reg:
; CHECK: or r24, r22
%result = or i8 %a, %b
ret i8 %result
}
define i8 @or8_reg_imm(i8 %a) {
; CHECK-LABEL: or8_reg_imm:
; CHECK: ori r24, 5
%result = or i8 %a, 5
ret i8 %result
}
define i16 @or16_reg_reg(i16 %a, i16 %b) {
; CHECK-LABEL: or16_reg_reg:
; CHECK: or r24, r22
; CHECK: or r25, r23
%result = or i16 %a, %b
ret i16 %result
}
define i16 @or16_reg_imm(i16 %a) {
; CHECK-LABEL: or16_reg_imm:
; CHECK: ori r24, 210
; CHECK: ori r25, 4
%result = or i16 %a, 1234
ret i16 %result
}
define i32 @or32_reg_reg(i32 %a, i32 %b) {
; CHECK-LABEL: or32_reg_reg:
; CHECK: or r22, r18
; CHECK: or r23, r19
; CHECK: or r24, r20
; CHECK: or r25, r21
%result = or i32 %a, %b
ret i32 %result
}
define i32 @or32_reg_imm(i32 %a) {
; CHECK-LABEL: or32_reg_imm:
; CHECK: ori r22, 21
; CHECK: ori r23, 205
; CHECK: ori r24, 91
; CHECK: ori r25, 7
%result = or i32 %a, 123456789
ret i32 %result
}
define i64 @or64_reg_reg(i64 %a, i64 %b) {
; CHECK-LABEL: or64_reg_reg:
; CHECK: or r18, r10
; CHECK: or r19, r11
; CHECK: or r20, r12
; CHECK: or r21, r13
; CHECK: or r22, r14
; CHECK: or r23, r15
; CHECK: or r24, r16
; CHECK: or r25, r17
%result = or i64 %a, %b
ret i64 %result
}
define i64 @or64_reg_imm(i64 %a) {
; CHECK-LABEL: or64_reg_imm:
; CHECK: ori r18, 204
; CHECK: ori r19, 204
; CHECK: ori r20, 204
; CHECK: ori r21, 204
; CHECK: ori r22, 204
; CHECK: ori r23, 204
; CHECK: ori r24, 204
; CHECK: ori r25, 204
%result = or i64 %a, 14757395258967641292
ret i64 %result
}

View File

@ -0,0 +1,70 @@
; RUN: llc < %s -march=avr -mattr=movw,lpm | FileCheck %s
; XFAIL: *
; Tests the standard LPM instruction
define i8 @test8(i8 addrspace(1)* %p) {
; CHECK-LABEL: test8:
; CHECK: movw r30, r24
; CHECK: lpm r24, Z
%1 = load i8, i8 addrspace(1)* %p
ret i8 %1
}
define i16 @test16(i16 addrspace(1)* %p) {
; CHECK-LABEL: test16:
; CHECK: movw r30, r24
; CHECK: lpm r24, Z+
; CHECK: lpm r25, Z+
%1 = load i16, i16 addrspace(1)* %p
ret i16 %1
}
define i8 @test8postinc(i8 addrspace(1)* %x, i8 %y) {
; CHECK-LABEL: test8postinc:
; CHECK: movw r30, r24
; CHECK: lpm {{.*}}, Z+
entry:
%cmp10 = icmp sgt i8 %y, 0
br i1 %cmp10, label %for.body, label %for.end
for.body: ; preds = %entry, %for.body
%ret.013 = phi i8 [ %add, %for.body ], [ 0, %entry ]
%i.012 = phi i8 [ %inc, %for.body ], [ 0, %entry ]
%x.addr.011 = phi i8 addrspace(1)* [ %incdec.ptr, %for.body ], [ %x, %entry ]
%incdec.ptr = getelementptr inbounds i8, i8 addrspace(1)* %x.addr.011, i16 1
%0 = load i8, i8 addrspace(1)* %x.addr.011
%add = add i8 %0, %ret.013
%inc = add i8 %i.012, 1
%exitcond = icmp eq i8 %inc, %y
br i1 %exitcond, label %for.end, label %for.body
for.end: ; preds = %for.body, %entry
%ret.0.lcssa = phi i8 [ 0, %entry ], [ %add, %for.body ]
ret i8 %ret.0.lcssa
}
define i16 @test16postinc(i16 addrspace(1)* %x, i8 %y) {
; CHECK-LABEL: test16postinc:
; CHECK: movw r30, r24
; CHECK: lpm {{.*}}, Z+
; CHECK: lpm {{.*}}, Z+
entry:
%cmp5 = icmp sgt i8 %y, 0
br i1 %cmp5, label %for.body, label %for.end
for.body: ; preds = %entry, %for.body
%ret.08 = phi i16 [ %add, %for.body ], [ 0, %entry ]
%i.07 = phi i8 [ %inc, %for.body ], [ 0, %entry ]
%x.addr.06 = phi i16 addrspace(1)* [ %incdec.ptr, %for.body ], [ %x, %entry ]
%incdec.ptr = getelementptr inbounds i16, i16 addrspace(1)* %x.addr.06, i16 1
%0 = load i16, i16 addrspace(1)* %x.addr.06
%add = add nsw i16 %0, %ret.08
%inc = add i8 %i.07, 1
%exitcond = icmp eq i8 %inc, %y
br i1 %exitcond, label %for.end, label %for.body
for.end: ; preds = %for.body, %entry
%ret.0.lcssa = phi i16 [ 0, %entry ], [ %add, %for.body ]
ret i16 %ret.0.lcssa
}

142
test/CodeGen/AVR/return.ll Normal file
View File

@ -0,0 +1,142 @@
; RUN: llc -mattr=avr6,sram < %s -march=avr | FileCheck %s
;TODO: test returning byval structs
; TODO: test naked functions
define void @return_void() {
; CHECK: return_void:{{[a-zA-Z0-9 #@]*}}
; CHECK-NEXT: #{{[a-zA-Z0-9 #@]*}}
; CHECK-NEXT: ret
ret void
}
define i8 @return8_imm() {
; CHECK-LABEL: return8_imm:
; CHECK: ldi r24, 5
ret i8 5
}
define i8 @return8_arg(i8 %x) {
; CHECK: return8_arg:{{[a-zA-Z0-9 #@]*}}
; CHECK-NEXT: #{{[a-zA-Z0-9 #@]*}}
; CHECK-NEXT: ret
ret i8 %x
}
define i8 @return8_arg2(i8 %x, i8 %y, i8 %z) {
; CHECK-LABEL: return8_arg2:
; CHECK: mov r24, r20
ret i8 %z
}
define i16 @return16_imm() {
; CHECK-LABEL: return16_imm:
; CHECK: ldi r24, 57
; CHECK: ldi r25, 48
ret i16 12345
}
define i16 @return16_arg(i16 %x) {
; CHECK: return16_arg:{{[a-zA-Z0-9 #@]*}}
; CHECK-NEXT: #{{[a-zA-Z0-9 #@]*}}
; CHECK-NEXT: ret
ret i16 %x
}
define i16 @return16_arg2(i16 %x, i16 %y, i16 %z) {
; CHECK-LABEL: return16_arg2:
; CHECK: movw r24, r20
ret i16 %z
}
define i32 @return32_imm() {
; CHECK-LABEL: return32_imm:
; CHECK: ldi r22, 21
; CHECK: ldi r23, 205
; CHECK: ldi r24, 91
; CHECK: ldi r25, 7
ret i32 123456789
}
define i32 @return32_arg(i32 %x) {
; CHECK: return32_arg:{{[a-zA-Z0-9 #@]*}}
; CHECK-NEXT: #{{[a-zA-Z0-9 #@]*}}
; CHECK-NEXT: ret
ret i32 %x
}
define i32 @return32_arg2(i32 %x, i32 %y, i32 %z) {
; CHECK-LABEL: return32_arg2:
; CHECK: movw r22, r14
; CHECK: movw r24, r16
ret i32 %z
}
define i64 @return64_imm() {
; CHECK-LABEL: return64_imm:
; CHECK: ldi r18, 204
; CHECK: ldi r19, 204
; CHECK: ldi r20, 104
; CHECK: ldi r21, 37
; CHECK: ldi r22, 25
; CHECK: ldi r23, 22
; CHECK: ldi r24, 236
; CHECK: ldi r25, 190
ret i64 13757395258967641292
}
define i64 @return64_arg(i64 %x) {
; CHECK: return64_arg:{{[a-zA-Z0-9 #@]*}}
; CHECK-NEXT: #{{[a-zA-Z0-9 #@]*}}
; CHECK-NEXT: ret
ret i64 %x
}
define i64 @return64_arg2(i64 %x, i64 %y, i64 %z) {
; CHECK-LABEL: return64_arg2:
; CHECK: push r28
; CHECK: push r29
; CHECK: ldd r18, Y+5
; CHECK: ldd r19, Y+6
; CHECK: ldd r20, Y+7
; CHECK: ldd r21, Y+8
; CHECK: ldd r22, Y+9
; CHECK: ldd r23, Y+10
; CHECK: ldd r24, Y+11
; CHECK: ldd r25, Y+12
; CHECK: pop r29
; CHECK: pop r28
ret i64 %z
}
define i32 @return64_trunc(i32 %a, i32 %b, i32 %c, i64 %d) {
; CHECK-LABEL: return64_trunc:
; CHECK: push r28
; CHECK: push r29
; CHECK: ldd r22, Y+5
; CHECK: ldd r23, Y+6
; CHECK: ldd r24, Y+7
; CHECK: ldd r25, Y+8
; CHECK: pop r29
; CHECK: pop r28
%result = trunc i64 %d to i32
ret i32 %result
}
define i32 @naked(i32 %x) naked {
; CHECK-LABEL: naked:
; CHECK-NOT: ret
ret i32 %x
}
define avr_intrcc void @interrupt_handler() {
; CHECK-LABEL: interrupt_handler:
; CHECK: reti
ret void
}
define avr_signalcc void @signal_handler() {
; CHECK-LABEL: signal_handler:
; CHECK: reti
ret void
}

29
test/CodeGen/AVR/sext.ll Normal file
View File

@ -0,0 +1,29 @@
; RUN: llc < %s -march=avr | FileCheck %s
; sext R17:R16, R13
; mov r16, r13
; mov r17, r13
; lsl r17
; sbc r17, r17
define i16 @sext1(i8 %x, i8 %y) {
; CHECK-LABEL: sext1:
; CHECK: mov r24, r22
; CHECK: mov r25, r22
; CHECK: lsl r25
; CHECK: sbc r25, r25
%1 = sext i8 %y to i16
ret i16 %1
}
; sext R17:R16, R16
; mov r17, r16
; lsl r17
; sbc r17, r17
define i16 @sext2(i8 %x) {
; CHECK-LABEL: sext2:
; CHECK: mov r25, r24
; CHECK: lsl r25
; CHECK: sbc r25, r25
%1 = sext i8 %x to i16
ret i16 %1
}

130
test/CodeGen/AVR/store.ll Normal file
View File

@ -0,0 +1,130 @@
; RUN: llc -mattr=avr6,sram < %s -march=avr | FileCheck %s
define void @store8(i8* %x, i8 %y) {
; CHECK-LABEL: store8:
; CHECK: st {{[XYZ]}}, r22
store i8 %y, i8* %x
ret void
}
define void @store16(i16* %x, i16 %y) {
; CHECK-LABEL: store16:
; CHECK: st {{[YZ]}}, r22
; CHECK: std {{[YZ]}}+1, r23
store i16 %y, i16* %x
ret void
}
define void @store8disp(i8* %x, i8 %y) {
; CHECK-LABEL: store8disp:
; CHECK: std {{[YZ]}}+63, r22
%arrayidx = getelementptr inbounds i8, i8* %x, i16 63
store i8 %y, i8* %arrayidx
ret void
}
define void @store8nodisp(i8* %x, i8 %y) {
; CHECK-LABEL: store8nodisp:
; CHECK: movw r26, r24
; CHECK: subi r26, 192
; CHECK: sbci r27, 255
; CHECK: st {{[XYZ]}}, r22
%arrayidx = getelementptr inbounds i8, i8* %x, i16 64
store i8 %y, i8* %arrayidx
ret void
}
define void @store16disp(i16* %x, i16 %y) {
; CHECK-LABEL: store16disp:
; CHECK: std {{[YZ]}}+62, r22
; CHECK: std {{[YZ]}}+63, r23
%arrayidx = getelementptr inbounds i16, i16* %x, i16 31
store i16 %y, i16* %arrayidx
ret void
}
define void @store16nodisp(i16* %x, i16 %y) {
; CHECK-LABEL: store16nodisp:
; CHECK: movw r30, r24
; CHECK: subi r30, 192
; CHECK: sbci r31, 255
; CHECK: st {{[YZ]}}, r22
; CHECK: std {{[YZ]}}+1, r23
%arrayidx = getelementptr inbounds i16, i16* %x, i16 32
store i16 %y, i16* %arrayidx
ret void
}
define void @store8postinc(i8* %x, i8 %y) {
; CHECK-LABEL: store8postinc:
; CHECK: st {{[XYZ]}}+, {{.*}}
entry:
%tobool3 = icmp eq i8 %y, 0
br i1 %tobool3, label %while.end, label %while.body
while.body: ; preds = %entry, %while.body
%dec5.in = phi i8 [ %dec5, %while.body ], [ %y, %entry ]
%x.addr.04 = phi i8* [ %incdec.ptr, %while.body ], [ %x, %entry ]
%dec5 = add i8 %dec5.in, -1
%incdec.ptr = getelementptr inbounds i8, i8* %x.addr.04, i16 1
store i8 %dec5, i8* %x.addr.04
%tobool = icmp eq i8 %dec5, 0
br i1 %tobool, label %while.end, label %while.body
while.end: ; preds = %while.body, %entry
ret void
}
define void @store16postinc(i16* %x, i16 %y) {
; CHECK-LABEL: store16postinc:
; CHECK: st {{[XYZ]}}+, {{.*}}
; CHECK: st {{[XYZ]}}+, {{.*}}
entry:
%tobool3 = icmp eq i16 %y, 0
br i1 %tobool3, label %while.end, label %while.body
while.body: ; preds = %entry, %while.body
%dec5.in = phi i16 [ %dec5, %while.body ], [ %y, %entry ]
%x.addr.04 = phi i16* [ %incdec.ptr, %while.body ], [ %x, %entry ]
%dec5 = add nsw i16 %dec5.in, -1
%incdec.ptr = getelementptr inbounds i16, i16* %x.addr.04, i16 1
store i16 %dec5, i16* %x.addr.04
%tobool = icmp eq i16 %dec5, 0
br i1 %tobool, label %while.end, label %while.body
while.end: ; preds = %while.body, %entry
ret void
}
define void @store8predec(i8* %x, i8 %y) {
; CHECK-LABEL: store8predec:
; CHECK: st -{{[XYZ]}}, {{.*}}
entry:
%tobool3 = icmp eq i8 %y, 0
br i1 %tobool3, label %while.end, label %while.body
while.body: ; preds = %entry, %while.body
%dec5.in = phi i8 [ %dec5, %while.body ], [ %y, %entry ]
%x.addr.04 = phi i8* [ %incdec.ptr, %while.body ], [ %x, %entry ]
%dec5 = add i8 %dec5.in, -1
%incdec.ptr = getelementptr inbounds i8, i8* %x.addr.04, i16 -1
store i8 %dec5, i8* %incdec.ptr
%tobool = icmp eq i8 %dec5, 0
br i1 %tobool, label %while.end, label %while.body
while.end: ; preds = %while.body, %entry
ret void
}
define void @store16predec(i16* %x, i16 %y) {
; CHECK-LABEL: store16predec:
; CHECK: st -{{[XYZ]}}, {{.*}}
; CHECK: st -{{[XYZ]}}, {{.*}}
entry:
%tobool3 = icmp eq i16 %y, 0
br i1 %tobool3, label %while.end, label %while.body
while.body: ; preds = %entry, %while.body
%dec5.in = phi i16 [ %dec5, %while.body ], [ %y, %entry ]
%x.addr.04 = phi i16* [ %incdec.ptr, %while.body ], [ %x, %entry ]
%dec5 = add nsw i16 %dec5.in, -1
%incdec.ptr = getelementptr inbounds i16, i16* %x.addr.04, i16 -1
store i16 %dec5, i16* %incdec.ptr
%tobool = icmp eq i16 %dec5, 0
br i1 %tobool, label %while.end, label %while.body
while.end: ; preds = %while.body, %entry
ret void
}

92
test/CodeGen/AVR/sub.ll Normal file
View File

@ -0,0 +1,92 @@
; RUN: llc < %s -march=avr | FileCheck %s
define i8 @sub8_reg_reg(i8 %a, i8 %b) {
; CHECK-LABEL: sub8_reg_reg:
; CHECK: sub r24, r22
%result = sub i8 %a, %b
ret i8 %result
}
define i8 @sub8_reg_imm(i8 %a) {
; CHECK-LABEL: sub8_reg_imm:
; CHECK: subi r24, 5
%result = sub i8 %a, 5
ret i8 %result
}
define i8 @sub8_reg_decrement(i8 %a) {
; CHECK-LABEL: sub8_reg_decrement:
; CHECK: dec r24
%result = sub i8 %a, 1
ret i8 %result
}
define i16 @sub16_reg_reg(i16 %a, i16 %b) {
; CHECK-LABEL: sub16_reg_reg:
; CHECK: sub r24, r22
; CHECK: sbc r25, r23
%result = sub i16 %a, %b
ret i16 %result
}
define i16 @sub16_reg_imm(i16 %a) {
; CHECK-LABEL: sub16_reg_imm:
; CHECK: sbiw r24, 63
%result = sub i16 %a, 63
ret i16 %result
}
define i16 @sub16_reg_imm_subi(i16 %a) {
; CHECK-LABEL: sub16_reg_imm_subi:
; CHECK: subi r24, 210
; CHECK: sbci r25, 4
%result = sub i16 %a, 1234
ret i16 %result
}
define i32 @sub32_reg_reg(i32 %a, i32 %b) {
; CHECK-LABEL: sub32_reg_reg:
; CHECK: sub r22, r18
; CHECK: sbc r23, r19
; CHECK: sbc r24, r20
; CHECK: sbc r25, r21
%result = sub i32 %a, %b
ret i32 %result
}
define i32 @sub32_reg_imm(i32 %a) {
; CHECK-LABEL: sub32_reg_imm:
; CHECK: subi r22, 21
; CHECK: sbci r23, 205
; CHECK: sbci r24, 91
; CHECK: sbci r25, 7
%result = sub i32 %a, 123456789
ret i32 %result
}
define i64 @sub64_reg_reg(i64 %a, i64 %b) {
; CHECK-LABEL: sub64_reg_reg:
; CHECK: sub r18, r10
; CHECK: sbc r20, r12
; CHECK: sbc r21, r13
; CHECK: sbc r22, r14
; CHECK: sbc r23, r15
; CHECK: sbc r24, r16
; CHECK: sbc r25, r17
%result = sub i64 %a, %b
ret i64 %result
}
define i64 @sub64_reg_imm(i64 %a) {
; CHECK-LABEL: sub64_reg_imm:
; CHECK: subi r18, 204
; CHECK: sbci r19, 204
; CHECK: sbci r20, 104
; CHECK: sbci r21, 37
; CHECK: sbci r22, 25
; CHECK: sbci r23, 22
; CHECK: sbci r24, 236
; CHECK: sbci r25, 190
%result = sub i64 %a, 13757395258967641292
ret i64 %result
}

View File

@ -0,0 +1,59 @@
; RUN: llc -mattr=sram,movw,addsubiw < %s -march=avr | FileCheck %s
declare void @llvm.va_start(i8*)
declare i16 @vsprintf(i8* nocapture, i8* nocapture, i8*)
declare void @llvm.va_end(i8*)
define i16 @varargs1(i8* nocapture %x, ...) {
; CHECK-LABEL: varargs1:
; CHECK: movw r20, r28
; CHECK: subi r20, 215
; CHECK: sbci r21, 255
; CHECK: movw r24, r28
; CHECK: adiw r24, 3
; CHECK: ldd r22, Y+39
; CHECK: ldd r23, Y+40
; CHECK: call
%buffer = alloca [32 x i8]
%ap = alloca i8*
%ap1 = bitcast i8** %ap to i8*
call void @llvm.va_start(i8* %ap1)
%arraydecay = getelementptr inbounds [32 x i8], [32 x i8]* %buffer, i16 0, i16 0
%1 = load i8*, i8** %ap
%call = call i16 @vsprintf(i8* %arraydecay, i8* %x, i8* %1)
call void @llvm.va_end(i8* %ap1)
ret i16 0
}
define i16 @varargs2(i8* nocapture %x, ...) {
; CHECK-LABEL: varargs2:
; CHECK: ld r24, Z
; CHECK: ldd r25, Z+1
%ap = alloca i8*
%ap1 = bitcast i8** %ap to i8*
call void @llvm.va_start(i8* %ap1)
%1 = va_arg i8** %ap, i16
call void @llvm.va_end(i8* %ap1)
ret i16 %1
}
declare void @var1223(i16, ...)
define void @varargcall() {
; CHECK-LABEL: varargcall:
; CHECK: ldi [[REG1:r[0-9]+]], 191
; CHECK: ldi [[REG2:r[0-9]+]], 223
; CHECK: push [[REG2]]
; CHECK: push [[REG1]]
; CHECK: ldi [[REG1:r[0-9]+]], 189
; CHECK: ldi [[REG2:r[0-9]+]], 205
; CHECK: push [[REG2]]
; CHECK: push [[REG1]]
; CHECK: ldi [[REG1:r[0-9]+]], 205
; CHECK: ldi [[REG2:r[0-9]+]], 171
; CHECK: push [[REG2]]
; CHECK: push [[REG1]]
; CHECK: call
; CHECK: adiw r30, 6
tail call void (i16, ...) @var1223(i16 -21555, i16 -12867, i16 -8257)
ret void
}

41
test/CodeGen/AVR/xor.ll Normal file
View File

@ -0,0 +1,41 @@
; RUN: llc < %s -march=avr | FileCheck %s
define i8 @xor8_reg_reg(i8 %a, i8 %b) {
; CHECK-LABEL: xor8_reg_reg:
; CHECK: eor r24, r22
%result = xor i8 %a, %b
ret i8 %result
}
define i16 @xor16_reg_reg(i16 %a, i16 %b) {
; CHECK-LABEL: xor16_reg_reg:
; CHECK: eor r24, r22
; CHECK: eor r25, r23
%result = xor i16 %a, %b
ret i16 %result
}
define i32 @xor32_reg_reg(i32 %a, i32 %b) {
; CHECK-LABEL: xor32_reg_reg:
; CHECK: eor r22, r18
; CHECK: eor r23, r19
; CHECK: eor r24, r20
; CHECK: eor r25, r21
%result = xor i32 %a, %b
ret i32 %result
}
define i64 @xor64_reg_reg(i64 %a, i64 %b) {
; CHECK-LABEL: xor64_reg_reg:
; CHECK: eor r18, r10
; CHECK: eor r19, r11
; CHECK: eor r20, r12
; CHECK: eor r21, r13
; CHECK: eor r22, r14
; CHECK: eor r23, r15
; CHECK: eor r24, r16
; CHECK: eor r25, r17
%result = xor i64 %a, %b
ret i64 %result
}

31
test/CodeGen/AVR/zext.ll Normal file
View File

@ -0,0 +1,31 @@
; RUN: llc < %s -march=avr | FileCheck %s
; zext R25:R24, R24
; eor R25, R25
define i16 @zext1(i8 %x) {
; CHECK-LABEL: zext1:
; CHECK: eor r25, r25
%1 = zext i8 %x to i16
ret i16 %1
}
; zext R25:R24, R20
; mov R24, R20
; eor R25, R25
define i16 @zext2(i8 %x, i8 %y) {
; CHECK-LABEL: zext2:
; CHECK: mov r24, r22
; CHECK: eor r25, r25
%1 = zext i8 %y to i16
ret i16 %1
}
; zext R25:R24, R24
; eor R25, R25
define i16 @zext_i1(i1 %x) {
; CHECK-LABEL: zext_i1:
; CHECK: eor r25, r25
%1 = zext i1 %x to i16
ret i16 %1
}