[AVR] Generate 'rcall' instead of 'call' on avr2 and avr25
authorBen Shi <ben.shi@streamcomputing.com>
Sun, 13 Mar 2022 06:35:49 +0000 (06:35 +0000)
committerBen Shi <ben.shi@streamcomputing.com>
Wed, 23 Mar 2022 02:00:15 +0000 (02:00 +0000)
The 'call' (long call) instruction is available on avr3 and above,
and devices in avr2 and avr25 should use the 'rcall' (short call)
instruction for function calls.

Reviewed By: aykevl, dylanmckay

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

llvm/lib/Target/AVR/AVRInstrInfo.td
llvm/test/CodeGen/AVR/call.ll

index 09e4398..c67f202 100644 (file)
@@ -194,6 +194,11 @@ def brtarget_13 : Operand<OtherVT> {
   let EncoderMethod = "encodeRelCondBrTarget<AVR::fixup_13_pcrel>";
 }
 
+def rcalltarget_13 : Operand<i16> {
+  let PrintMethod = "printPCRelImm";
+  let EncoderMethod = "encodeRelCondBrTarget<AVR::fixup_13_pcrel>";
+}
+
 // The target of a 22 or 16-bit call/jmp instruction.
 def call_target : Operand<iPTR> {
   let EncoderMethod = "encodeCallTarget";
@@ -965,10 +970,8 @@ let isBarrier = 1, isBranch = 1, isTerminator = 1 in {
 let isCall = 1 in {
   // SP is marked as a use to prevent stack-pointer assignments that appear
   // immediately before calls from potentially appearing dead.
-  let Uses = [SP] in def RCALLk : FBRk<1, (outs),
-                                       (ins brtarget_13
-                                        : $target),
-                                       "rcall\t$target", []>;
+  let Uses = [SP] in def RCALLk : FBRk<1, (outs), (ins rcalltarget_13:$k),
+                                       "rcall\t$k", [(AVRcall imm:$k)]>;
 
   // SP is marked as a use to prevent stack-pointer assignments that appear
   // immediately before calls from potentially appearing dead.
@@ -985,13 +988,10 @@ let isCall = 1 in {
   // SP is marked as a use to prevent stack-pointer assignments that appear
   // immediately before calls from potentially appearing dead.
   //
-  //: TODO: the imm field can be either 16 or 22 bits in devices with more
+  // TODO: the imm field can be either 16 or 22 bits in devices with more
   // than 64k of ROM, fix it once we support the largest devices.
-  let Uses = [SP] in def CALLk : F32BRk<0b111, (outs),
-                                        (ins call_target
-                                         : $k),
-                                        "call\t$k", [(AVRcall imm
-                                                      : $k)]>,
+  let Uses = [SP] in def CALLk : F32BRk<0b111, (outs), (ins call_target:$k),
+                                        "call\t$k", [(AVRcall imm:$k)]>,
       Requires<[HasJMPCALL]>;
 }
 
@@ -2448,8 +2448,12 @@ def : Pat<(adde i8
                      : $src2))>;
 
 // Calls.
-def : Pat<(AVRcall(i16 tglobaladdr : $dst)), (CALLk tglobaladdr : $dst)>;
-def : Pat<(AVRcall(i16 texternalsym : $dst)), (CALLk texternalsym : $dst)>;
+let Predicates = [HasJMPCALL] in {
+  def : Pat<(AVRcall(i16 tglobaladdr:$dst)), (CALLk tglobaladdr:$dst)>;
+  def : Pat<(AVRcall(i16 texternalsym:$dst)), (CALLk texternalsym:$dst)>;
+}
+def : Pat<(AVRcall(i16 tglobaladdr:$dst)), (RCALLk tglobaladdr:$dst)>;
+def : Pat<(AVRcall(i16 texternalsym:$dst)), (RCALLk texternalsym:$dst)>;
 
 // `anyext`
 def : Pat<(i16(anyext i8
index 7d94f9b..ec91480 100644 (file)
@@ -1,4 +1,5 @@
-; RUN: llc < %s -march=avr -mattr=avr6 | FileCheck %s
+; RUN: llc < %s -mtriple=avr -mcpu=avr6 | FileCheck %s --check-prefixes=CHECK,AVR6
+; RUN: llc < %s -mtriple=avr -mcpu=avr2 | FileCheck %s --check-prefixes=CHECK,AVR2
 
 ; TODO: test returning byval structs
 
@@ -18,11 +19,13 @@ declare i64 @foo64_2(i64, i64, i64)
 define i8 @calli8_reg() {
 ; CHECK-LABEL: calli8_reg:
 ; CHECK: ldi r24, 12
-; CHECK: call foo8_1
+; AVR6:  call foo8_1
+; AVR2:  rcall foo8_1
 ; CHECK: ldi r24, 12
 ; CHECK: ldi r22, 13
 ; CHECK: ldi r20, 14
-; CHECK: call foo8_2
+; AVR6:  call foo8_2
+; AVR2:  rcall foo8_2
     %result1 = call i8 @foo8_1(i8 12)
     %result2 = call i8 @foo8_2(i8 12, i8 13, i8 14)
     ret i8 %result2
@@ -34,7 +37,8 @@ define i8 @calli8_stack() {
 ; CHECK: ldi [[REG2:r[0-9]+]], 11
 ; CHECK: std Z+1, [[REG1]]
 ; CHECK: std Z+2, [[REG2]]
-; CHECK: call foo8_3
+; AVR6:  call foo8_3
+; AVR2:  rcall 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
 }
@@ -45,7 +49,8 @@ define i16 @calli16_reg() {
 ; CHECK: ldi r25, 2
 ; CHECK: ldi r22, 2
 ; CHECK: ldi r23, 2
-; CHECK: call foo16_1
+; AVR6:  call foo16_1
+; AVR2:  rcall foo16_1
     %result1 = call i16 @foo16_1(i16 513, i16 514)
     ret i16 %result1
 }
@@ -60,7 +65,8 @@ define i16 @calli16_stack() {
 ; CHECK: ldi [[REG2:r[0-9]+]], 2
 ; CHECK: std Z+1, [[REG1]]
 ; CHECK: std Z+2, [[REG2]]
-; CHECK: call foo16_2
+; AVR6:  call foo16_2
+; AVR2:  rcall 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
 }
@@ -75,7 +81,8 @@ define i32 @calli32_reg() {
 ; CHECK: ldi r19, 132
 ; CHECK: ldi r20, 30
 ; CHECK: ldi r21, 2
-; CHECK: call foo32_1
+; AVR6:  call foo32_1
+; AVR2:  rcall foo32_1
     %result1 = call i32 @foo32_1(i32 34554432, i32 35554432)
     ret i32 %result1
 }
@@ -90,7 +97,8 @@ define i32 @calli32_stack() {
 ; CHECK: ldi [[REG2:r[0-9]+]], 66
 ; CHECK: std Z+1, [[REG1]]
 ; CHECK: std Z+2, [[REG2]]
-; CHECK: call foo32_2
+; AVR6:  call foo32_2
+; AVR2:  rcall foo32_2
     %result1 = call i32 @foo32_2(i32 1, i32 2, i32 3, i32 4, i32 34554432)
     ret i32 %result1
 }
@@ -105,7 +113,8 @@ define i64 @calli64_reg() {
 ; CHECK: ldi r23, 73
 ; CHECK: ldi r24, 31
 ; CHECK: ldi r25, 242
-; CHECK: call foo64_1
+; AVR6:  call foo64_1
+; AVR2:  rcall foo64_1
     %result1 = call i64 @foo64_1(i64 17446744073709551615)
     ret i64 %result1
 }
@@ -129,7 +138,8 @@ define i64 @calli64_stack() {
 ; CHECK: ldi [[REG2:r[0-9]+]], 255
 ; CHECK: std Z+1, [[REG1]]
 ; CHECK: std Z+2, [[REG2]]
-; CHECK: call foo64_2
+; AVR6:  call foo64_2
+; AVR2:  rcall foo64_2
     %result1 = call i64 @foo64_2(i64 1, i64 2, i64 17446744073709551615)
     ret i64 %result1
 }
@@ -171,7 +181,9 @@ define void @testcallprologue() {
 
 define i32 @icall(i32 (i32) addrspace(1)* %foo) {
 ; CHECK-LABEL: icall:
-; CHECK: movw r30, r24
+; AVR6:  movw r30, r24
+; AVR2:  mov r30, r24
+; AVR2:  mov r31, r25
 ; CHECK: ldi r22, 147
 ; CHECK: ldi r23, 248
 ; CHECK: ldi r24, 214
@@ -192,14 +204,28 @@ 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
+; AVR6:  movw [[REG0:(r[0-9]+|[XYZ])]], r24
+; AVR6:  movw [[REG1:(r[0-9]+|[XYZ])]], r22
+; AVR6:  movw r22, r18
+; AVR6:  movw r24, r20
+; AVR6:  movw r18, [[REG1]]
+; AVR6:  movw r20, [[REG0]]
+; AVR6:  call __divsf3
+; AVR6:  call foofloat
+; AVR2:  mov [[REG0:(r[0-9]+)]], r24
+; AVR2:  mov [[REG1:(r[0-9]+)]], r25
+; AVR2:  mov [[REG2:(r[0-9]+)]], r22
+; AVR2:  mov [[REG3:(r[0-9]+)]], r23
+; AVR2:  mov r22, r18
+; AVR2:  mov r23, r19
+; AVR2:  mov r24, r20
+; AVR2:  mov r25, r21
+; AVR2:  mov r18, [[REG2]]
+; AVR2:  mov r19, [[REG3]]
+; AVR2:  mov r20, [[REG0]]
+; AVR2:  mov r21, [[REG1]]
+; AVR2:  rcall __divsf3
+; AVR2:  rcall foofloat
 ; CHECK: subi r22, 251
 ; CHECK: sbci r23, 255
 ; CHECK: sbci r24, 255