| 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] |