public inbox for gcc@gcc.gnu.org
 help / color / mirror / Atom feed
From: Richard Sandiford <richard.sandiford@arm.com>
To: Andras Tantos <andras@tantosonline.com>
Cc: gcc@gcc.gnu.org
Subject: Re: How to generate a call inst. sequence?
Date: Wed, 19 Jan 2022 10:45:28 +0000	[thread overview]
Message-ID: <mptbl08ovg7.fsf@arm.com> (raw)
In-Reply-To: <e26871d2-11f5-585b-36ad-e8a49d202ac5@tantosonline.com> (Andras Tantos's message of "Tue, 18 Jan 2022 20:53:43 -0800")

Andras Tantos <andras@tantosonline.com> writes:
> All,
>
> I'm working on porting GCC to a processor architecture that doesn't have 
> a (HW) stack nor a call instruction. This means that for calls, I need 
> to generate the following instruction sequence:
>
>      // move stack-pointer:
>      $sp <- $sp-4
>      // load return address:
>      $r3 <- return_label
>      // store return address on stack:
>      mem[$sp] <- $r3
>      // jump to callee:
>      $pc <- <address_of_function>

Even though this is internally a jump, it still needs to be represented
as a (call …) rtx in rtl, and emitted using emit_call_insn.

In other words, the "call" expander must always emit a call_insn
of some kind.  (But it can emit other instructions too, such as the
ones you describe above.)

Richard

>    return_label:
>
> Now, I can do all of that as a multi-instruction string sequence in my 
> .md file (which is what I'm doing right now), but there are two problems 
> with that approach. First, it hard-codes the temp register ($r3 above) 
> and requires me to reserve it even though it could be used between calls 
> by the register allocator. Second this approach (I think at least) 
> prevents any passes from merging stack-frame preparation for the call 
> arguments, such as eliminating the stack-pointer update above.
>
> I thought I could circumvent these problems by emitting a piece of RTL 
> in the 'call' pattern:
>
>    (define_expand "call"
>      [(call
>        (match_operand:QI 0 "memory_operand" "")
>        (match_operand 1 "" "")
>      )]
>      ""
>    {
>      brew_expand_call(Pmode, operands);
>    })
>
> where brew_expand_call is:
>
>    void brew_expand_call(machine_mode mode, rtx *operands)
>    {
>      gcc_assert (MEM_P(operands[0]));
>
>      rtx_code_label *label = gen_label_rtx();
>      rtx label_ref = gen_rtx_LABEL_REF(SImode, label);
>      rtx temp_reg = gen_reg_rtx(mode);
>
>      // $sp <- $sp - 4
>      emit_insn(gen_subsi3(
>        stack_pointer_rtx,
>        stack_pointer_rtx,
>        GEN_INT(4)
>      ));
>      // $r3 <- <ret_label>
>      emit_insn(gen_move_insn(
>        temp_reg,
>        label_ref
>      ));
>      // mem[$sp] <- $r3
>      emit_insn(gen_move_insn(
>        gen_rtx_MEM(Pmode, stack_pointer_rtx),
>        temp_reg
>      ));
>      emit_jump_insn(gen_jump(operands[0]));
>      emit_label(label);
>    }
>
> If I try to compile the following test:
>
>    void x(void)
>    {
>    }
>
>    int main(void)
>    {
>      x();
>      return 0;
>    }
>
> I get an assert:
>
>    during RTL pass: expand
>    dump file: call.c.252r.expand
>    call.c: In function ‘main’:
>    call.c:9:1: internal compiler error: in as_a, at is-a.h:242
>        9 | }
>          | ^
>    0x6999b7 rtx_insn* as_a<rtx_insn*, rtx_def>(rtx_def*)
>        ../../brew-gcc/gcc/is-a.h:242
>    0x6999b7 rtx_sequence::insn(int) const
>        ../../brew-gcc/gcc/rtl.h:1439
>    0x6999b7 mark_jump_label_1
>        ../../brew-gcc/gcc/jump.cc:1077
>    0xcfc31f mark_jump_label_1
>        ../../brew-gcc/gcc/jump.cc:1171
>    0xcfc73d mark_all_labels
>        ../../brew-gcc/gcc/jump.cc:332
>    0xcfc73d rebuild_jump_labels_1
>        ../../brew-gcc/gcc/jump.cc:74
>    0x9e8e62 execute
>        ../../brew-gcc/gcc/cfgexpand.cc:6845
>
> The reference dump file:
>
>    ;; Function x (x, funcdef_no=0, decl_uid=1383, cgraph_uid=1, 
> symbol_order=0)
>
>
>    ;; Generating RTL for gimple basic block 2
>
>
>    try_optimize_cfg iteration 1
>
>    Merging block 3 into block 2...
>    Merged blocks 2 and 3.
>    Merged 2 and 3 without moving.
>    Merging block 4 into block 2...
>    Merged blocks 2 and 4.
>    Merged 2 and 4 without moving.
>
>
>    try_optimize_cfg iteration 2
>
>
>
>    ;;
>    ;; Full RTL generated for this function:
>    ;;
>    (note 1 0 3 NOTE_INSN_DELETED)
>    (note 3 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
>    (note 2 3 0 2 NOTE_INSN_FUNCTION_BEG)
>
>    ;; Function main (main, funcdef_no=1, decl_uid=1386, cgraph_uid=2, 
> symbol_order=1)
>
>
>    ;; Generating RTL for gimple basic block 2
>
>    ;; Generating RTL for gimple basic block 3
>
>
>
>    EMERGENCY DUMP:
>
>    int main ()
>    {
>    (note 3 1 2 4 [bb 4] NOTE_INSN_BASIC_BLOCK)
>    (note 2 3 4 4 NOTE_INSN_FUNCTION_BEG)
>
>    (note 4 2 5 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
>    (insn 5 4 6 2 (set (reg/f:SI 1 $sp)
>            (minus:SI (reg/f:SI 1 $sp)
>                (const_int 4 [0x4]))) "call.c":7:5 -1
>        (nil))
>    (insn 6 5 7 2 (set (reg:SI 25)
>            (label_ref:SI 9)) "call.c":7:5 -1
>        (insn_list:REG_LABEL_OPERAND 9 (nil)))
>    (insn 7 6 8 2 (set (mem:SI (reg/f:SI 1 $sp) [0  S4 A32])
>            (reg:SI 25)) "call.c":7:5 -1
>        (nil))
>    (jump_insn 8 7 9 2 (set (pc)
>            (label_ref (mem:QI (symbol_ref:SI ("x") [flags 0x3] 
> <function_decl 0x7f594efa9200 x>) [0 x S1 A8]))) "call.c":7:5 -1
>        (nil))
>    (code_label 9 8 10 2 3 (nil) [1 uses])
>    (call_insn 10 9 11 2 (call (mem:QI (symbol_ref:SI ("x") [flags 0x3]  
> <function_decl 0x7f594efa9200 x>) [0 x S1 A8])
>            (const_int 16 [0x10])) "call.c":7:5 -1
>        (nil)
>        (nil))
>    (insn 11 10 12 2 (set (reg:SI 23 [ _3 ])
>            (const_int 0 [0])) "call.c":8:12 -1
>        (nil))
>
>    (code_label 12 11 13 3 4 (nil) [0 uses])
>    (note 13 12 14 3 [bb 3] NOTE_INSN_BASIC_BLOCK)
>    (insn 14 13 15 3 (set (reg:SI 24 [ <retval> ])
>            (reg:SI 23 [ _3 ])) "call.c":9:1 -1
>        (nil))
>    (jump_insn 15 14 16 3 (set (pc)
>            (label_ref 17)) "call.c":9:1 -1
>        (nil))
>
>    (code_label 17 16 20 5 2 (nil) [0 uses])
>    (note 20 17 18 5 [bb 5] NOTE_INSN_BASIC_BLOCK)
>    (insn 18 20 19 5 (set (reg/i:SI 4 $r4)
>            (reg:SI 24 [ <retval> ])) "call.c":9:1 -1
>        (nil))
>    (insn 19 18 0 5 (use (reg/i:SI 4 $r4)) "call.c":9:1 -1
>        (nil))
>
>    }
>
> As a test to narrow the problem down, I removed the 'emit_jump_insn' 
> call above. That generated an assembly (thus proving the theory that the 
> assert has something to do with that), but then the assembly doesn't 
> contain my label, only a reference to it; which of course later on would 
> result in a linker error.
>
> So, what am I doing wrong and how can I achieve what I want?

  reply	other threads:[~2022-01-19 10:45 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-01-19  4:53 Andras Tantos
2022-01-19 10:45 ` Richard Sandiford [this message]
2022-01-20 23:47   ` Andras Tantos

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=mptbl08ovg7.fsf@arm.com \
    --to=richard.sandiford@arm.com \
    --cc=andras@tantosonline.com \
    --cc=gcc@gcc.gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).