Skip to content

Commit

Permalink
[AVR] Generate 'rcall' instead of 'call' on avr2 and avr25
Browse files Browse the repository at this point in the history
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
  • Loading branch information
benshi001 committed Mar 23, 2022
1 parent 6edfe45 commit 4563893
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 31 deletions.
28 changes: 16 additions & 12 deletions llvm/lib/Target/AVR/AVRInstrInfo.td
Expand Up @@ -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";
Expand Down Expand Up @@ -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.
Expand All @@ -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]>;
}

Expand Down Expand Up @@ -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
Expand Down
64 changes: 45 additions & 19 deletions llvm/test/CodeGen/AVR/call.ll
@@ -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

Expand All @@ -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
Expand All @@ -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
}
Expand All @@ -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
}
Expand All @@ -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
}
Expand All @@ -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
}
Expand All @@ -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
}
Expand All @@ -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
}
Expand All @@ -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
}
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down

0 comments on commit 4563893

Please sign in to comment.