YaK:: How GCC adds, for a Motorola 6809 [Changes]   [Calendar]   [Search]   [Index]   [PhotoTags]   
[mega_changes]
[photos]

How GCC adds, for a Motorola 6809

http://wiki.yak.net/1166

Here's a short C program "zadd.c"

int count;

void Increment(int addend) {
  count = count + addend;
}

We have a 15 year old compiler (circa 2007) for the Motorola 6809 8-bit processor (circa 1977).

Let's compile that file into assembly:

$ gcc6809 -O2 -S zadd.c

;;; gcc for m6809 : Nov 22 2019 00:09:58
;;; 4.6.4 (gcc6809lw pl6)
;;; ABI version 1
;;; -mint16
        .module        zadd.c
        .area .text
        .globl _Increment
_Increment:
        pshs        u
        leau        ,s
        ldd        _count
        leax        d,x
        stx        _count
        puls        u,pc
        .area .bss
        .globl        _count
_count:        .blkb        2

For the function Increment, removing the preamble (pshs, leau) and the postamble (puls), this is the guts of the function.

        ldd        _count
        leax        d,x
        stx        _count

About this compiler and the 6809:

  • "int" is 16 bits (that is, 2 bytes).

  • The 6809 contains (among other things) five 16-bit registers: D, X, Y, U, S. (S is the stack pointer. Usually U is the frame pointer.)

  • In this compiler, the first 16-bit argument arrives in the X register (and a 16-bit result would be returned in the X register).

    Let's see how GCC created that. First it builds a list of abstract (architecture-neutral) instructions:

    $ gcc6809 -O2 -fdump-rtl-expand -S zadd.c

    GCC's code generation rules are written in this pseudo-lisp language called RTL.

    Nontrivial items from zadd.c.144r.expand:

    (insn 2 4 3 2 (set (reg/v:HI 30 [ addend ])
            (reg:HI 1 x [ addend ])) zadd.c:3 -1
         (nil))
    
    (insn 6 5 7 3 (set (mem/c/i:HI (symbol_ref:HI ("count")  <var_decl 0x7f99e9204000 count>) [2 count+0 S2 A8])
            (plus:HI (mem/c/i:HI (symbol_ref:HI ("count")  <var_decl 0x7f99e9204000 count>) [2 count+0 S2 A8])
                (reg/v:HI 30 [ addend ]))) zadd.c:4 -1
         (nil))
    

    Here is a much-simplified version:

      (set (reg 30) (reg 1 "x")  ;  LET reg30 = reg"x"
    
      (set (mem "count") (plus (mem "count") (reg 30)) ; LET count = count + reg30
    

    If use the -dP option, it'll put the RTL as comments in the assembly, and identify exactly which rules generated them.

    $ gcc6809 -O2 -fdump-rtl-expand -dP -S zadd.c

    ; (insn 11 3 6 (set (reg:HI 6 d)
    ;         (mem/c/i:HI (symbol_ref:HI ("count")  <var_decl 0x7f2b2fe04000 count>) [2 count+0 S2 A8])) zadd.c:4 10 {*movhi_1}
    ;      (nil))
            ldd        _count        ;  11        *movhi_1/4        [length = 4]
    ; (insn 6 11 10 (set (reg:HI 1 x)
    ;         (plus:HI (reg:HI 6 d)
    ;             (reg/v:HI 1 x [orig:30 addend ] [30]))) zadd.c:4 26 {addhi3}
    ;      (expr_list:REG_DEAD (reg:HI 6 d)
    ;         (nil)))
            leax        d,x        ;  6        addhi3/4        [length = 4]
    ; (insn 10 6 15 (set (mem/c/i:HI (symbol_ref:HI ("count")  <var_decl 0x7f2b2fe04000 count>) [2 count+0 S2 A8])
    ;         (reg:HI 1 x)) zadd.c:4 10 {*movhi_1}
    ;      (expr_list:REG_DEAD (reg:HI 1 x)
    ;         (nil)))
            stx        _count        ;  10        *movhi_1/5        [length = 4]
    

    The most interesting instruction is the middle one, "leax d,x", formed by a rule named addhi3 with the constraint alternative 4.

    Here's the definition of addh3. The constraints have 8 alternatives

    gitlab.com/dfffffff/gcc6809/gcc/config/m6809/m6809.md

    (define_insn "addhi3"
      [(set (match_operand:HI 0 "nonimmediate_operand"      "=d, d,  d,  a,?a, a,???T,a")
        (plus:HI(match_operand:HI 1 "add_general_operand"   "%0, 0,  0,  d, 0, a, 0, a")
        (match_operand:HI 2 "general_operand"               " 0, !U, mi, a, m, d, T, i")
      ))]
      ""
      "@
       lslb\t\t;addhi: R:%0 += R:%2\;rola\t\t;also R:%0 *= 2
       pshs\t%2\t;addhi: R:%0 += R:%2\;add%0\t,s++
       add%0\t%2
       lea%0\t%1,%2
       #
       lea%0\t%2,%1
       #
       lea%0\t%a2,%1"
       [(set_attr "length" "2,6,*,*,7,*,7,*")])
    

    The 4th set of constraints

    a, d, a, (read vertically)

    causes the 4th line after the "@" to be emitted:

    lea%0\t%1,%2

    and expanding %0=`x` ; %1=`d` ; %2=`x` that becomes

    leax d,x



















  • (unless otherwise marked) Copyright 2002-2014 YakPeople. All rights reserved.
    (last modified 2023-01-21)       [Login]
    (No back references.)