YaK:: How GCC adds, for a Motorola 6809 | [Changes] [Calendar] [Search] [Index] [PhotoTags] |
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:
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
(last modified 2023-01-21) [Login] |