diff options
| -rw-r--r-- | llvm/test/CodeGen/MSP430/callee-saved.ll | 38 | ||||
| -rw-r--r-- | llvm/test/CodeGen/MSP430/calls.ll | 22 | ||||
| -rw-r--r-- | llvm/test/CodeGen/MSP430/cc_args.ll | 79 | ||||
| -rw-r--r-- | llvm/test/CodeGen/MSP430/interrupt.ll | 49 | ||||
| -rw-r--r-- | llvm/test/CodeGen/MSP430/struct-return.ll | 36 | 
5 files changed, 222 insertions, 2 deletions
diff --git a/llvm/test/CodeGen/MSP430/callee-saved.ll b/llvm/test/CodeGen/MSP430/callee-saved.ll new file mode 100644 index 00000000000..76db4dcdfe8 --- /dev/null +++ b/llvm/test/CodeGen/MSP430/callee-saved.ll @@ -0,0 +1,38 @@ +; RUN: llc < %s | FileCheck %s + +target datalayout = "e-m:e-p:16:16-i32:16-i64:16-f32:16-f64:16-a:8-n8:16-S16" +target triple = "msp430-generic-generic" + +; Test the r4-r10 callee-saved registers (MSP430 EABI p. 3.2.2). + +@g = global float 0.0 + +define void @foo() { +; CHECK-LABEL: foo: +; CHECK-NOT: push	r15 +; CHECK-NOT: push	r14 +; CHECK-NOT: push	r13 +; CHECK-NOT: push	r12 +; CHECK-NOT: push	r11 +; CHECK: push	r10 +; CHECK: push	r9 +; CHECK: push	r8 +; CHECK: push	r7 +; CHECK: push	r6 +; CHECK: push	r5 +; CHECK: push	r4 +  %t1 = load volatile float, float* @g +  %t2 = load volatile float, float* @g +  %t3 = load volatile float, float* @g +  %t4 = load volatile float, float* @g +  %t5 = load volatile float, float* @g +  %t6 = load volatile float, float* @g +  %t7 = load volatile float, float* @g +  store volatile float %t1, float* @g +  store volatile float %t2, float* @g +  store volatile float %t3, float* @g +  store volatile float %t4, float* @g +  store volatile float %t5, float* @g +  store volatile float %t6, float* @g +  ret void +} diff --git a/llvm/test/CodeGen/MSP430/calls.ll b/llvm/test/CodeGen/MSP430/calls.ll new file mode 100644 index 00000000000..c5540bf1f99 --- /dev/null +++ b/llvm/test/CodeGen/MSP430/calls.ll @@ -0,0 +1,22 @@ +; RUN: llc < %s | FileCheck %s + +target datalayout = "e-p:16:16:16-i8:8:8-i16:16:16-i32:16:32-n8:16-a0:16:16" +target triple = "msp430---elf" + +declare i32 @direct(i32 %a) + +define i32 @test_direct(i32 %a) nounwind { +; CHECK-LABEL: test_direct: +; CHECK: call #direct +  %1 = call i32 @direct(i32 %a) +  ret i32 %1 +} + +define i16 @test_indirect(i16 (i16)* %a, i16 %b) nounwind { +; CHECK-LABEL: test_indirect: +; CHECK: mov	r12, r14 +; CHECK: mov	r13, r12 +; CHECK: call	r14 +  %1 = call i16 %a(i16 %b) +  ret i16 %1 +} diff --git a/llvm/test/CodeGen/MSP430/cc_args.ll b/llvm/test/CodeGen/MSP430/cc_args.ll index eb7e470a9b6..c8164f1291d 100644 --- a/llvm/test/CodeGen/MSP430/cc_args.ll +++ b/llvm/test/CodeGen/MSP430/cc_args.ll @@ -54,6 +54,29 @@ entry:  ; CHECK: call #f_i16_i64_i16    call void @f_i16_i64_i16(i16 1, i64 72623859790382856, i16 2) +; Check that r15 is not used and the last i32 argument passed through the stack. +; CHECK: mov	#258, 10(r1) +; CHECK: mov	#772, 8(r1) +; CHECK: mov	#258, 6(r1) +; CHECK: mov	#772, 4(r1) +; CHECK: mov	#1286, 2(r1) +; CHECK: mov	#1800, 0(r1) +; CHECK: mov	#1, r12 +; CHECK: mov	#772, r13 +; CHECK: mov	#258, r14 +  call void @f_i16_i64_i32_i32(i16 1, i64 72623859790382856, i32 16909060, i32 16909060) + +; CHECK: mov	#258, 6(r1) +; CHECK: mov	#772, 4(r1) +; CHECK: mov	#1286, 2(r1) +; CHECK: mov	#1800, 0(r1) +; CHECK: mov	#1800, r12 +; CHECK: mov	#1286, r13 +; CHECK: mov	#772, r14 +; CHECK: mov	#258, r15 +; CHECK: call	#f_i64_i64 +  call void @f_i64_i64(i64 72623859790382856, i64 72623859790382856) +    ret void  } @@ -136,4 +159,60 @@ define void @f_i16_i64_i16(i16 %a, i64 %b, i16 %c) #0 {    ret void  } +define void @f_i64_i64(i64 %a, i64 %b) #0 { +; CHECK: f_i64_i64: +; CHECK: mov	r15, &g_i64+6 +; CHECK: mov	r14, &g_i64+4 +; CHECK: mov	r13, &g_i64+2 +; CHECK: mov	r12, &g_i64 +  store volatile i64 %a, i64* @g_i64, align 2 +; CHECK: mov	10(r4), &g_i64+6 +; CHECK: mov	8(r4), &g_i64+4 +; CHECK: mov	6(r4), &g_i64+2 +; CHECK: mov	4(r4), &g_i64 +  store volatile i64 %b, i64* @g_i64, align 2 +  ret void +} + +define void @f_i16_i64_i32_i32(i16 %a, i64 %b, i32 %c, i32 %d) #0 { +; CHECK-LABEL: f_i16_i64_i32_i32: +; CHECK: mov	r12, &g_i16 +  store volatile i16 %a, i16* @g_i16, align 2 +; CHECK: mov	10(r4), &g_i64+6 +; CHECK: mov	8(r4), &g_i64+4 +; CHECK: mov	6(r4), &g_i64+2 +; CHECK: mov	4(r4), &g_i64 +  store volatile i64 %b, i64* @g_i64, align 2 +; CHECK: mov	r14, &g_i32+2 +; CHECK: mov	r13, &g_i32 +  store volatile i32 %c, i32* @g_i32, align 2 +; CHECK: mov	14(r4), &g_i32+2 +; CHECK: mov	12(r4), &g_i32 +  store volatile i32 %d, i32* @g_i32, align 2 +  ret void +} +; MSP430 EABI p. 6.3 +; For helper functions which take two long long arguments +; the first argument is passed in R8::R11 and the second argument +; is in R12::R15. + +@g_i64_2 = common global i64 0, align 2 + +define i64 @helper_call_i64() #0 { +  %1 = load i64, i64* @g_i64, align 2 +  %2 = load i64, i64* @g_i64_2, align 2 +; CHECK-LABEL: helper_call_i64: +; CHECK: mov	&g_i64, r8 +; CHECK: mov	&g_i64+2, r9 +; CHECK: mov	&g_i64+4, r10 +; CHECK: mov	&g_i64+6, r11 +; CHECK: mov	&g_i64_2, r12 +; CHECK: mov	&g_i64_2+2, r13 +; CHECK: mov	&g_i64_2+4, r14 +; CHECK: mov	&g_i64_2+6, r15 +; CHECK: call	#__mspabi_divlli +  %3 = sdiv i64 %1, %2 +  ret i64 %3 +} +  attributes #0 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf"="true" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "unsafe-fp-math"="false" "use-soft-float"="false" } diff --git a/llvm/test/CodeGen/MSP430/interrupt.ll b/llvm/test/CodeGen/MSP430/interrupt.ll new file mode 100644 index 00000000000..5fa0c849c26 --- /dev/null +++ b/llvm/test/CodeGen/MSP430/interrupt.ll @@ -0,0 +1,49 @@ +; RUN: llc < %s | FileCheck %s + +target datalayout = "e-m:e-p:16:16-i32:16-i64:16-f32:16-f64:16-a:8-n8:16-S16" +target triple = "msp430-generic-generic" + +@llvm.used = appending global [1 x i8*] [i8* bitcast (void ()* @ISR to i8*)], section "llvm.metadata" + +; MSP430 EABI p. 3.9 +; Interrupt functions must save all the registers that are used, even those +; that are normally considered callee-saved. + +; To return from an interrupt function, the function must execute the special +; instruction RETI, which restores the SR register and branches to the PC where +; the interrupt occurred. + +@g = global float 0.0 + +define msp430_intrcc void @ISR() #0 { +entry: +; CHECK-LABEL: ISR: +; CHECK: push	r15 +; CHECK: push	r14 +; CHECK: push	r13 +; CHECK: push	r12 +; CHECK: push	r11 +; CHECK: push	r10 +; CHECK: push	r9 +; CHECK: push	r8 +; CHECK: push	r7 +; CHECK: push	r6 +; CHECK: push	r5 +; CHECK: push	r4 +  %t1 = load volatile float, float* @g +  %t2 = load volatile float, float* @g +  %t3 = load volatile float, float* @g +  %t4 = load volatile float, float* @g +  %t5 = load volatile float, float* @g +  %t6 = load volatile float, float* @g +  %t7 = load volatile float, float* @g +  store volatile float %t1, float* @g +  store volatile float %t2, float* @g +  store volatile float %t3, float* @g +  store volatile float %t4, float* @g +  store volatile float %t5, float* @g +  store volatile float %t6, float* @g +; CHECK: reti +  ret void +} + diff --git a/llvm/test/CodeGen/MSP430/struct-return.ll b/llvm/test/CodeGen/MSP430/struct-return.ll index a52ea1b702a..8f662897a29 100644 --- a/llvm/test/CodeGen/MSP430/struct-return.ll +++ b/llvm/test/CodeGen/MSP430/struct-return.ll @@ -3,7 +3,7 @@  target datalayout = "e-p:16:16:16-i8:8:8-i16:16:16-i32:16:32-n8:16"  target triple = "msp430---elf" -; Allow simple structures to be returned by value. +; Pass large structures by reference (MSP430 EABI p. 3.5)  %s = type { i64, i64 } @@ -17,7 +17,39 @@ define %s @fred() #0 {  ; CHECK: mov	#772, 4(r12)  ; CHECK: mov	#1286, 2(r12)  ; CHECK: mov	#1800, 0(r12) -  ret %s {i64 72623859790382856, i64 651345242494996224}  +  ret %s {i64 72623859790382856, i64 651345242494996224} +} + +%struct.S = type { i16, i16, i16 } + +@a = common global i16 0, align 2 +@b = common global i16 0, align 2 +@c = common global i16 0, align 2 + +define void @test() #1 { +; CHECK-LABEL: test: +  %1 = alloca %struct.S, align 2 +; CHECK:      mov	r1, r12 +; CHECK-NEXT: call	#sret +  call void @sret(%struct.S* nonnull sret %1) #3 +  ret void +} + +define void @sret(%struct.S* noalias nocapture sret) #0 { +; CHECK-LABEL: sret: +; CHECK: mov	&a, 0(r12) +; CHECK: mov	&b, 2(r12) +; CHECK: mov	&c, 4(r12) +  %2 = getelementptr inbounds %struct.S, %struct.S* %0, i16 0, i32 0 +  %3 = load i16, i16* @a, align 2 +  store i16 %3, i16* %2, align 2 +  %4 = getelementptr inbounds %struct.S, %struct.S* %0, i16 0, i32 1 +  %5 = load i16, i16* @b, align 2 +  store i16 %5, i16* %4, align 2 +  %6 = getelementptr inbounds %struct.S, %struct.S* %0, i16 0, i32 2 +  %7 = load i16, i16* @c, align 2 +  store i16 %7, i16* %6, align 2 +  ret void  }  attributes #0 = { nounwind }  | 

